TypeScript SDK for the put.io API
Domain-first, schema-validated at the boundary, and designed for all runtimes.
Install with npm:
npm install @putdotio/sdkimport { createPutioSdkPromiseClient } from "@putdotio/sdk";
const sdk = createPutioSdkPromiseClient({
accessToken: process.env.PUTIO_TOKEN,
});
const account = await sdk.account.getInfo({
download_token: 1,
});The SDK can also be created without a default token:
const sdk = createPutioSdkPromiseClient();
const validation = await sdk.auth.validateToken(process.env.PUTIO_TOKEN!);Shared formatting, URL, and error-localization helpers are available from the utilities subpath:
import {
FileURLProvider,
secondsToReadableDuration,
toHumanFileSize,
} from "@putdotio/sdk/utilities";const size = toHumanFileSize(1_572_864);
const duration = secondsToReadableDuration(444);import { Effect } from "effect";
import { createPutioSdkEffectClient, makePutioSdkLiveLayer } from "@putdotio/sdk";
const sdk = createPutioSdkEffectClient();
const program = sdk.files
.list(0, {
per_page: 20,
total: 1,
})
.pipe(Effect.provide(makePutioSdkLiveLayer({ accessToken: process.env.PUTIO_TOKEN! })));
const result = await Effect.runPromise(program);makePutioSdkLiveLayer(...) provides both the SDK config and the default fetch-backed HttpClient.
Use makePutioSdkLayer(...) only when you want to supply your own HttpClient service.
Both client styles expose the same domain surface:
promiseClient.files.list(0, { per_page: 20 });
effectClient.files.list(0, { per_page: 20 });Choose the Promise client when you want standard async functions. Choose the Effect client when you want the canonical typed error channel and Effect-native composition.
| Client | Use it for |
|---|---|
createPutioSdkPromiseClient(config) |
React apps, scripts, server handlers, React Query |
createPutioSdkEffectClient() |
Effect-native workflows and service composition |
Effect is the canonical typed surface. The Promise client is an adapter for environments that want standard async functions.
- SDK creation does not require an access token
- Authenticated endpoints need a token through client config or the Effect layer config
- Effect client: keeps errors in the Effect error channel with operation-specific typing
- Promise client: throws tagged SDK error objects such as
PutioOperationError,PutioApiError, andPutioRateLimitError - Promise client: owns a managed Effect runtime and exposes
dispose()for explicit teardown
If you create a long-lived Promise client in a script, test harness, or server integration, call await sdk.dispose() during teardown.
| Namespace | Purpose |
|---|---|
account |
account info, settings, confirmations, destructive account actions |
auth |
token validation, login flows, device/OOB helpers, two-factor flows |
config |
app-owned JSON config storage |
downloadLinks |
download-link bundles |
events |
history events and event torrent payloads |
family |
family members and invites |
files |
file listing, search, move/delete/extract, MP4, direct access URLs, upload |
friendInvites |
friend invitation management |
friends |
friend graph and requests |
ifttt |
IFTTT integration endpoints |
oauth |
OAuth app management |
payment |
plans, vouchers, payment flows, payment history |
rss |
RSS feed management |
sharing |
friend shares, public shares, clone flows |
transfers |
transfer list, add/retry/cancel/clean flows |
trash |
trash listing, restore, delete, empty |
tunnel |
route listing |
utilities |
file URLs, localized errors, and shared formatting helpers |
zips |
zip creation and lookup |
- schema-first contracts at every external boundary
- typed errors are first-class
- parameter-conditioned responses are modeled explicitly
- no compatibility namespace shims in the public API
- fetch-native core with runtime-portable Web APIs
The package is designed around standard Web APIs. Host runtimes should provide:
fetchRequest,Response, andHeadersURLandURLSearchParamsAbortControllerFormDatabtoafor username/password auth flows such asauth.login(...)
For upload flows, the host should also provide file-compatible inputs such as File or Blob.
If a target runtime is missing these APIs, provide them with host-level polyfills or adapters instead of patching the SDK surface.
Promise consumers receive tagged SDK error objects:
import {
PutioOperationError,
PutioRateLimitError,
createPutioSdkPromiseClient,
} from "@putdotio/sdk";
const sdk = createPutioSdkPromiseClient({
accessToken: process.env.PUTIO_TOKEN,
});
try {
await sdk.files.createFolder({
name: "",
parent_id: 0,
});
} catch (error) {
if (error instanceof PutioOperationError) {
if (error.operation === "createFolder") {
console.log(error.body.error_type);
}
}
if (error instanceof PutioRateLimitError) {
console.log(error.retryAfter);
}
}Effect consumers keep errors in the typed error channel instead of throwing:
import { Effect } from "effect";
import { createPutioSdkEffectClient, makePutioSdkLiveLayer } from "@putdotio/sdk";
const sdk = createPutioSdkEffectClient();
const handled = sdk.files
.createFolder({
name: "",
parent_id: 0,
})
.pipe(
Effect.catchTag("PutioOperationError", (error) => {
if (error.operation === "createFolder") {
return Effect.succeed(error.body.error_type);
}
return Effect.fail(error);
}),
Effect.provide(makePutioSdkLiveLayer({ accessToken: process.env.PUTIO_TOKEN! })),
);files exposes both JSON contracts and direct route helpers:
const playlistUrl = await sdk.files.getHlsStreamUrl(fileId, {
maxSubtitleCount: 1,
});
const upload = await sdk.files.upload({
file: new File(["hello"], "hello.txt"),
parentId: 0,
});Upload targets upload.put.io internally because api.put.io/v2/files/upload is only a redirect shim.
The Promise client plugs into TanStack Query directly:
import { useQuery } from "@tanstack/react-query";
import { createPutioSdkPromiseClient } from "@putdotio/sdk";
const sdk = createPutioSdkPromiseClient({
accessToken: token,
});
export const useAccountInfo = () =>
useQuery({
queryKey: ["account", "info"],
queryFn: () => sdk.account.getInfo({ download_token: 1 }),
});The Effect client also works well when you want the canonical typed API:
import { useQuery } from "@tanstack/react-query";
import { Effect } from "effect";
import { createPutioSdkEffectClient, makePutioSdkLiveLayer } from "@putdotio/sdk";
const sdk = createPutioSdkEffectClient();
const sdkLayer = makePutioSdkLiveLayer({
accessToken: token,
});
export const useFiles = (parentId: number) =>
useQuery({
queryKey: ["files", parentId],
queryFn: () =>
Effect.runPromise(sdk.files.list(parentId, { per_page: 50 }).pipe(Effect.provide(sdkLayer))),
});- docs/ARCHITECTURE.md for package shape and boundaries
- docs/TESTING.md for local and live verification
- docs/READINESS.md for domain readiness
- docs/RELEASE.md for release automation
- SECURITY.md for private-first vulnerability disclosure
Contributor setup, validation, and live-test workflow live in CONTRIBUTING.md.
This project is available under the MIT License.
