@apostra/sdk) is the first Apostra SDK package planned for
npm. The Python SDK (apostra) is coming after its model generator is ready.
Registry publication and the live synthetic-seller check are still pending, so
use the V3 HTTP API until the TypeScript package is published.
Both clients expose the same 58 generated operations, including two public
document reads, from the OpenAPI 3.1 document. They call
HTTP directly and need no MCP session or LLM. TypeScript requires Node.js
22.18+; Python requires 3.11+.
For installation and a first campaign preview, see the SDK quickstart.
Release notes
SDK changes are generated and checked against the committed OpenAPI on every pull request. The release workflow can publish TypeScript, Python or both after a reviewer approves the selected package artifacts and their synthetic evidence. Each package compares its proposed version with its own latest published version and will not publish the same or an older version. Removing an operation needs a major version increase, or a minor increase while the SDK is below 1.0.Make typed calls
After publication:apostra.models. Input field names
remain the wire names. TypeScript exports named GetDeliveryInput and
GetDeliveryResult types, plus wire models at @apostra/sdk/models. Both
languages return the success envelope’s data directly. Schema patterns,
length limits, conditional requirements and permissions are checked by the API.
Inspect a successful response
Each generated method also has a response variant for support and observability work. TypeScript appendsWithResponse; Python appends _with_response.
These variants keep the normal method’s input and write-idempotency rules, and
return the result data, request ID and response headers (plus HTTP status).
Use the returned request ID to correlate a successful call with support, and
handle headers as potentially sensitive transport metadata rather than logging
them indiscriminately.
Credentials and accounts
Choose exactly one of an API key, an existing REST/M2M access token, or an injected token provider. Providers obtain and refresh tokens in your application; the SDK invokes them for each request and never replays a failed 401 request. The async Python client uses an async provider. MCP-audience OAuth tokens are not REST credentials. See Authentication. For a deployed backend using OAuth client credentials, use the SDK helper with the client ID, client secret and scope returned when the M2M application was created. It retains a token only in memory, refreshes it 60 seconds before expiry, and shares one in-flight refresh between concurrent calls. Keep the client secret in your server-side secrets manager. Do not use this helper in a browser or log its inputs or result. Token refreshes have a 30-second deadline by default; usetimeoutMs in TypeScript or timeout in Python to override it.
APOSTRA_API_KEY, APOSTRA_ACCOUNT_ID and
APOSTRA_BASE_URL from the environment. Explicit constructor options override
the environment values. The base URL must use HTTPS, except for a loopback URL
used in local development.
Keep keys on the server. Do not put them in browser bundles, URLs or logs.
There is no SDK credential store. Requests send a versioned user agent and the
explicit account header, with no additional telemetry request.
A per-call accountId (Python: account_id) overrides the client default.
It selects only an account the credential can resolve and must match that
resolved account. It does not switch an MCP session or expand permissions.
Errors, retries and cancellation
ApostraError exposes HTTP status, code, recovery, retry timing, and the
request ID. Catch typed errors such as RateLimitError and ValidationError;
unknown error codes remain strings, so new server codes stay readable.
Malformed responses raise ProtocolError; transport failures retain the
underlying fetch/httpx exception. Default exception strings omit response text.
Calls time out after 30 seconds and retry transient network, 429 and 5xx
failures twice by default with full-jitter backoff. Set maxRetries (Python:
max_retries) to 0 to opt out. Reads retry automatically. Writes replay only
with their required caller-owned idempotency key; the SDK neither generates nor
replaces it. The server’s retry_after is a minimum delay. Preserve the
operation’s original idempotencyKey, clientRequestId or other
operation-specific key; these fields are not interchangeable.
A 202 raises InFlightReceiptError rather than returning a completed result.
It carries only the request ID and Retry-After delay while the receipt schema
and read-only receipt endpoint are pending. Use settle (settle_async for
async Python) to replay the same keyed operation until it settles, with a
deadline and cancellation. It never creates a replacement key.
TypeScript accepts an AbortSignal. Python async calls support task cancellation
and timeouts. Cancelling HTTP does not undo server work. A server mutation must
use the operation’s existing state transition if cancellation is supported.
TypeScript timeouts cover token acquisition, HTTP and response-body consumption.
Async Python timeouts cover the awaited provider and HTTP call. A synchronous
Python provider is caller-bounded: a blocked provider raises TimeoutError
before dispatch, while httpx uses the same timeout for the HTTP call.
Pages and asynchronous work
paginate (paginate_async in async Python) accepts a read callback and a
next-cursor callback. Keep the original query, limit and account fixed. Search
uses objects.nextCursor; delivery uses page.nextCursor. Delivery pages are
live per call, not a snapshot. Document sections also require the original
applicability.asOf value. Cursors are opaque and cannot cross queries.
poll accepts a read callback and completion predicate. Python requires a
timeout; TypeScript requires a cancellation signal. For proposal requests,
keep the original body, revision and idempotency key, and distinguish result
pagination from capability pagination. The helper does not choose business
states or retry failed requests.
TypeScript read callbacks receive the helper’s cancellation signal. Forward it
to each SDK call so cancellation reaches the HTTP request:
Human steps and unsupported helpers
uploadCreativeAsset / upload_creative_asset returns the typed current human
task and fallback_url. Some UI results expose optional openInBrowserUrl;
others expose parameters only. The SDK never invents a URL from those parameters.
Import TypeScript verifyWebhook from the server-only
@apostra/sdk/webhooks subpath; it does not load into the browser-safe SDK root.
verifyWebhook / verify_webhook verifies the raw V3 webhook body with
duplicate-preserving signature, timestamp, and delivery-ID headers. It rejects
duplicate headers, uses constant-time HMAC comparison, enforces the five-minute
window, and selects the secret by key ID so callers can keep both rotation keys.
openHandoff / open_handoff returns an actual HTTPS URL supplied by the
caller. It opens nothing in headless code. Interactive applications can inject
an opener. There is no embedded UI, OAuth login flow, wait/resume protocol, or
byte-upload helper in the current SDK contract.
Those helpers need a public contract before they can be supported.
getHandoff / get_handoff narrows an operation result to a supported typed
handoff (kind, url, expiresAt, resume) or returns null / None.
Pass that value to openHandoff / open_handoff; headless code only returns
the supplied HTTPS URL and interactive applications can inject an opener. A
browser opening or closing is not completion: follow resume and read the
affected object before continuing. The SDK never constructs a URL or embeds an
OAuth login flow.