SDK Architecture
The Pinner SDK is built around one core class: Pinner. Everything flows through it.
The Pinner class
Pinner is the entry point. You create an instance with your configuration and then access all functionality through property-access namespaces:
pinner.upload: upload files, directories, JSON, CAR data, and morepinner.pins: check status, update metadata, list and manage pinspinner.ipns: create and manage IPNS keys and publish recordspinner.websites: publish content as a website with SSL support
Each namespace groups related operations together. You pass your JWT once in the configuration; the Pinner instance handles authentication for everything.
Upload: callable namespace and builder
The upload property is unique: it works as both a direct method and a builder namespace. This is implemented via a JavaScript Proxy that delegates to whichever side you need:
- As a method:
pinner.upload(file, options): upload a file immediately - As a namespace:
pinner.upload.file(file),pinner.upload.json(data), and so on: returns a builder for chaining options
Builder pattern
When you use the builder namespace, each content method returns a typed builder you chain options onto before calling .pin() to commit the upload:
- Choose what to upload:
.file(),.json(),.base64(),.url(),.csv(),.text(),.raw() - Optionally chain
.name(),.keyvalues(),.waitForOperation(), or.operationPollingOptions() - Call
.pin()to execute
This keeps the API composable; you only specify what you need, and each step returns a type-safe builder for the next.
Convenience methods
Beyond the builder, Pinner also exposes shorthand methods for common workflows:
uploadAndWait(): upload a file and wait for the result in one callwaitForOperation(): poll an operation until it reaches a settled stateuploadDirectory(): upload an array of files as a directory (preprocessed to CAR internally)uploadCar(): upload a raw CAR file without preprocessing
Upload pipeline: XHR vs TUS
The UploadManager selects a transport strategy based on file size:
- Small files (below the account's upload limit, defaulting to 100 MB) use XHR upload
- Large files use TUS resumable upload
Both transports are built on Uppy internally. CAR files are automatically detected by MIME type or extension, or can be forced via the isCarFile option.
Pinata adapters
Pinner ships with two adapter functions that wrap a Pinner instance in a Pinata SDK-compatible interface:
pinataAdapter: matches Pinata SDK 2.x API shape (namespaced withupload.public,files.public, etc.)pinataLegacyAdapter: matches Pinata SDK 1.x API shape (flat methods likepinFileToIPFS,pinJSONToIPFS)
The adapters translate Pinata-style calls into Pinner operations behind the scenes. Features that Pinner does not support (groups, analytics, private uploads, signed URLs) return empty data or throw a "not supported" error. Your existing Pinata code can migrate with only the initialization changed.
Error hierarchy
Errors in the SDK follow a single-root hierarchy so you can catch at the granularity you need:
PinnerError: base class for all SDK errors; carries acode, aretryableflag, and an optionalcauseConfigurationError: missing or invalid configuration (not retryable)AuthenticationError: JWT or access failure (not retryable)EnvironmentError: unsupported runtime environment (not retryable)UploadError: any upload failureNetworkError: request-level failure (retryable)ValidationError: invalid input; includes an optionalfieldEmptyFileError: zero-byte file upload attempt
TimeoutError: request exceeded its deadline (retryable)
PinError: any pin-management failureNotFoundError: pin or resource does not exist (not retryable)RateLimitError: too many requests; includesretryAfterseconds (retryable)
The retryable flag on PinnerError lets you decide programmatically whether to retry. The SDK also exports type-guard functions: isRetryable(error) and isAuthenticationError(error) for common checks.
Key design principles
- One entry point. Create a
Pinnerinstance once, use it everywhere. - Dual-mode namespace.
uploadis both a direct method and a builder namespace, via aProxy. - Builder pattern for uploads. Start with a content method, chain options, commit with
.pin(). - Automatic transport selection. XHR for small uploads, TUS for large; transparent to the caller.
- Adapter compatibility. Pinata SDK 2.x and 1.x drop-in replacements for easy migration.