Install and use the Qoder Cloud Agents TypeScript SDK, including types, asynchronous calls, streaming responses, cancellation, pagination, and custom fetch.
The Qoder Cloud Agents TypeScript SDK works with TypeScript and JavaScript applications. It provides Forward and Managed clients, request and response types, asynchronous pagination, and SSE streaming. The package offers both ES Modules and CommonJS entry points.
Requires Node.js 20.12 or later:
Keep the package version and lockfile in version control. The examples in this document run on a Node.js server.
Save your personal access token (PAT) in an environment variable:
Use the Forward client to create a template and identity, start a session, and send a message. Save the following code as an
Use the Managed client to create an Agent and environment, start a session, and send a message:
You can also import the corresponding clients from
Explicit configuration takes precedence over environment variables. Default PAT mode reads
Time values are in milliseconds. Per-call request options are usually the last method argument. Methods with query or body parameters require those parameters first; do not mix the two.
Passing new
Pass a personal access token explicitly with
After setting
Multiple clients can share a credential instance and cache. For the China site, set both
Import request and response types from the subpath for the corresponding mode. Fields retain the API snake_case names:
Whether a field accepts
An ordinary stream ends at EOF. To continue subscribing after a recoverable disconnection, explicitly use
Replace
Use
By default, requests are retried up to 2 times, for a maximum of 3 attempts. Automatic retries require safe replayability:
Within these rules, the SDK handles server retry hints and delays. Some APIs apply stricter rules. Set the default count with the client
For write requests, pass an idempotency key through
The default timeout is 10 minutes.
The application can also hold an
Signal cancellation ends waiting, retries, and response body reads for the call. Work performed by custom middleware or external credential components should also follow their own cancellation and resource management contracts.
List methods support asynchronous iteration, fetching subsequent pages on demand:
To process one page at a time, read
You can also iterate pages with
Ordinary requests return an
Use
This measures elapsed time until the response arrives, not until SSE consumption finishes. Middleware is part of the API request pipeline, not a global interceptor for every external connection.
Use
Installation
Requires Node.js 20.12 or later:
Basic usage
Save your personal access token (PAT) in an environment variable:
.mjs file to run it directly, or use it in a TypeScript project supporting ES Modules:
qca-sdk/forward and qca-sdk/managed. In CommonJS projects, use require('qca-sdk') and place await calls inside an asynchronous function.
In subsequent snippets that do not recreate client, it refers to a configured Forward client. Replace IDs such as sess_example with real IDs accessible to the current credentials. See the Managed quickstart and Forward API reference for more integration instructions.
Client configuration
| Configuration | Forward | Managed |
|---|---|---|
| Client | ForwardClient | ManagedClient |
| Base URL environment variable | QODER_FORWARD_BASE_URL | QODER_BASE_URL |
| Global default URL | https://api.qoder.com/api/v1/forward | https://api.qoder.com/api/v1/cloud |
| CN URL | https://api.qoder.com.cn/api/v1/forward | https://api.qoder.com.cn/api/v1/cloud |
QODER_ACCESS_TOKEN first, then QODER_PAT. The SDK does not automatically load .env files. The Base URL must include the full API prefix and match the region of the account, credentials, and resources.
Reusing configuration
withOptions() creates a new client of the same type, retaining settings that are not overridden. The original client keeps its configuration:
defaultHeaders, defaultQuery, or middleware replaces the entire corresponding configuration value. Per-request options still take precedence over the derived client defaults.
Authentication
PAT
Pass a personal access token explicitly with pat, or use environment variables. Keep access tokens in a trusted server environment; frontend applications access QCA through their own backend services.
Service Account
After setting QODER_SA_KEY, explicitly create a credential component. It exchanges and caches SATs (service account tokens), refreshing them when subsequent requests require it:
region: 'cn' and a CN Base URL. For Managed-only access, you can request the qca.access scope; permissions and workspace bindings must be configured on the server.
Ordinary clients do not automatically enable token exchange merely because QODER_SA_KEY exists in the environment. An SA Key cannot serve directly as a business API access token. SA authentication failures do not fall back to PAT.
If the application manages SATs itself, use { authMode: 'sa', accessToken: token }. accessToken also accepts a function returning a token or Promise<string>, evaluated before each request attempt. The application must refresh static SATs; do not configure multiple sources such as accessToken, pat, and credential together. See the authentication documentation.
Request and response types
Import request and response types from the subpath for the corresponding mode. Fields retain the API snake_case names:
| JavaScript value | JSON object field behavior |
|---|---|
Omitted property or undefined value | Omit the field |
null | Send null |
false, 0, '' | Send as is |
| Empty array or object | Send [] or {} |
null and how that value is handled are defined by the corresponding API. Narrow union types using their discriminator or property checks before reading specific fields.
Unknown response fields added by the server are preserved, but may not yet appear in the current TypeScript declarations. Check their actual values before declaring the extension types your application needs. TypeScript types alone do not provide runtime data validation.
Streaming responses
streamEvents() returns an asynchronously iterable SSE stream. Read it with for await...of and release the connection in finally:
resumableStream():
evt_checkpoint with a valid resume position; omit last_event_id for an initial subscription. resumableStream() directly returns an asynchronous iterable and does not need await when created. The example uses AbortSignal to limit the whole subscription to 60 seconds; deadline cancellation propagates to the caller as a cancellation error.
A resumable stream retains the SSE cursor of the most recently delivered event and reuses it when reconnecting. It does not resend business requests or guarantee exactly-once processing. Multiple deltas for one event may share an ID; do not discard all repeated frames solely by ID.
Without a cursor, the stream starts at the current event stream tail; reading history requires a valid historical resume position. HTTP request retry counts are not the reconnection limit for the whole subscription. See the API definitions for event meanings and task completion conditions.
Closing a stream or cancelling a local HTTP request ends only the current subscription; it does not automatically stop execution already started in the cloud.
Error handling and Request ID
Use instanceof to distinguish caller cancellation, timeouts, HTTP errors, and other cases:
APIError covers HTTP, connection, timeout, and cancellation errors. Without an HTTP response, status, headers, and response may be undefined; do not assume they always exist. Client configuration errors belong to the broader QoderError class.
Common HTTP subclasses include BadRequestError (400), AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404), ConflictError (409), RateLimitError (429), and InternalServerError (5xx).
For ordinary JSON object responses, _request_id comes from response headers and is null when absent. It is non-enumerable and does not appear in JSON.stringify() or object spread results. HTTP errors expose the identifier through request_id. Use .withResponse() to read response metadata alongside pagination or streams. Individual stream events and nested objects do not automatically carry this metadata.
Retries and idempotency
By default, requests are retried up to 2 times, for a maximum of 3 attempts. Automatic retries require safe replayability:
| Request | Retried by default for |
|---|---|
| GET, HEAD, or requests with an idempotency key | Connection errors, timeouts, 408, 429, 5xx |
| Other requests without an idempotency key | 429 |
| 409 response | No automatic retries |
Request body is a non-replayable ReadableStream | No automatic replay |
maxRetries option, or override it in per-call request options:
idempotencyKey in request options. Reuse the same key for all retries of one logical operation; use a new key for a new operation.
Timeouts and cancellation
The default timeout is 10 minutes. timeout controls how long each underlying fetch waits for a response: timing starts before calling fetch and ends when response headers arrive. It excludes earlier credential acquisition, middleware execution, and subsequent response body reads.
SSE or download reads can therefore exceed timeout. To limit the total duration of an operation, pass an AbortSignal:
AbortController and call abort() when the user cancels:
Pagination
List methods support asynchronous iteration, fetching subsequent pages on demand:
.data and check whether a next page exists:
for await (const currentPage of page.iterPages()). getNextPage() throws when there is no next page, rather than returning null; automatic iteration ends normally on the last page. Paginators retain filters and request configuration.
Advanced configuration
Raw responses
Ordinary requests return an APIPromise. Direct await yields parsed data; .withResponse() returns the data, raw response, and Request ID together:
.asResponse() returns the raw Response without reading its body. The caller must consume or cancel the body:
Custom fetch and middleware
Use fetch to inject an HTTP implementation. The chosen implementation manages proxies, TLS, and connection pools. Middleware observes or adjusts each API request attempt:
headers and query in request options for additional headers and query parameters. Request fields not yet covered by types can be placed in parameter objects; only fields supported by the server take effect. Prefer existing typed methods for ordinary calls.