@postinger/api-client
v0.2.1
Published
Typed client for the Postinger public API
Readme
@postinger/api-client
Typed Node.js client for Postinger's project-scoped public API. Requires Node.js >=24.15.0.
Published as @postinger/api-client; version 0.2.0 adds renewable CLI device credentials.
Version 0.2.1 defaults new connections to the production API at https://api.postinger.dev. Existing saved server URLs remain unchanged.
import { PostingerClient } from '@postinger/api-client';
const api = new PostingerClient({
baseUrl: process.env.POSTINGER_API_URL!,
apiKey: process.env.POSTINGER_API_KEY!,
});
const accounts = await api.listAccounts();
const session = await api.session();
const capabilities = await api.publishingCapabilities(accounts.data[0].id);
const draft = await api.createDraft({ content: 'Hello', targets: [], mediaIds: [] }, 'my-logical-draft-1');
const report = await api.analyticsReport({ from: '2026-09-01', to: '2026-09-13' });baseUrl is the backend origin or its /public/v1 URL. HTTPS is required except on localhost. There is no implicit production destination. Redirects are rejected to keep credentials on the configured API. Use a customer pst_... key, not an Unkey root key.
Methods cover session verification, account publishing capabilities, post creation/editing/scheduling/publishing/deletion, signed media upload operations, and all five analytics endpoints. session() verifies any active key without requiring resource permissions and returns project, expiry and effective permissions. publishingCapabilities(accountId) needs accounts-read and returns rules shared with backend validation; check available before publishing. createDraft rejects scheduling fields; use createPost to schedule. Post updates preserve omitted fields. The PostingerClient upload methods return signed URLs; they do not read files or upload bytes themselves. Never attach the customer API key when sending bytes to storage.
Each result contains { data, meta: { requestId } }. Creation and publication also return idempotencyKey. Pass a stable key for a logical operation; reuse it and the same body for manual retries within the API's 24-hour window. Generated keys are reused within automatic retries. A new method call with no supplied key is a new operation.
Requests time out after 30 seconds. Up to two retries are attempted only for GET and writes with server-supported idempotency, on transport failures, 429, 502/503/504 or idempotency_in_progress. Long Retry-After values (>2s) are returned to the caller instead of holding the process. PATCH, DELETE and upload mutations are not automatically retried. An uncertain write may have succeeded; inspect its state and use the returned idempotency key where applicable.
PostingerError includes code, status, requestId, retryAfterSeconds and idempotencyKey when available. errorDetails() provides a serializable, sanitized error. Inputs are validated locally and authoritatively again by the API. Session responses are validated at runtime and unknown fields are removed; other response types describe the API contract without runtime validation.
listPosts returns one page. Use iteratePosts for async iteration; analytics pagination uses postAnalytics({ cursor }). Keep filters stable between pages. Analytics metrics retain decimal strings, nulls, freshness, and coverage fields without numeric coercion.
From the repository root: pnpm build:tools and pnpm test:tools.
Shared CLI/MCP helpers
The Node-only subpaths keep authentication and local uploads consistent between both tools:
import { resolveCredentials } from '@postinger/api-client/credentials';
import { uploadFile } from '@postinger/api-client/upload';
const api = new PostingerClient(await resolveCredentials());
const media = await uploadFile(api, '/absolute/path/photo.jpg');resolveCredentials(apiUrl?, env?) uses environment credentials first, then the owner-readable CLI config, enforcing saved API origin binding and refusing unconfirmed device logins. It defaults to DEFAULT_API_URL (https://api.postinger.dev) when no explicit or saved URL applies. An environment key ignores the saved credential file; pair it with POSTINGER_API_URL for a custom server. The credentials subpath also exports configPath, readConfig, saveConfig and logout for CLI use. For a saved device session, resolution may call /cli/auth/refresh and returns a getApiKey callback. Pass the whole resolved object to PostingerClient so long-running clients renew the same device session before requests. Refreshed access tokens are cached in memory, without overwriting another process's saved login. The refresh secret is stable until session expiry/disconnect, making concurrent commands and uncertain refresh responses safe. Explicit API keys are never refreshed. Resolution does not open a browser.
uploadFile(api, path, onProgress?, { signal }?) streams a local JPEG/PNG/MP4/MOV through reservation, transfer and validation. Large videos use up to three concurrent parts. Unlike the low-level client methods, this helper retries idempotent transfer/completion steps with bounded backoff, including rate-limit waits. Reservation creation is not retried. It returns the final ApiResult<Media>, never publishes, and never sends API credentials to storage. The caller must authorize filesystem access; the MCP wrapper enforces its configured media directory. Cancellation aborts transfers/backoff and stops subsequent steps, but an in-flight API request may already have completed.
