Install and use the Qoder Cloud Agents Python SDK, including synchronous and asynchronous calls, data types, streaming responses, retries, and HTTP configuration.
The Qoder Cloud Agents Python SDK provides synchronous and asynchronous Forward and Managed clients, with typed request parameters, Pydantic response models, automatic pagination, and SSE streaming.
Requires Python 3.10 or later:
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:
Use the Managed client to create an Agent and environment, start a session, and send a message:
Individual requests can override
Set your personal access token (PAT) with the
Set
Use synchronous credentials with synchronous clients, and
The application owns the credential. Closing a business API client does not close the credential. Close all clients using it before closing the credential; the nested context managers above release resources in this order.
Ordinary clients do not automatically read an SA Key and exchange it for a token, and an SA Key cannot serve directly as a business API access token. SA authentication failures do not fall back to PAT. If your application manages SATs itself, use
Asynchronous clients use
In an already running event loop, directly
Request parameters use
Whether a field accepts
Responses use Pydantic models. Read fields through attributes and serialize with
Consume a single SSE connection with a context manager, which releases the connection on exit:
For the asynchronous version, wait for the connection to be established before entering the asynchronous context:
Ordinary
Asynchronous
Request errors inherit from
Common HTTP exceptions include
By default, requests are retried up to 2 times, for a maximum of 3 attempts:
Requests must also meet constraints such as safe replayability; some APIs apply stricter rules. Within these rules, the SDK handles server retry hints and uses valid server-specified delays or exponential backoff.
Set
The default connection timeout is 5 seconds. Read, write, and connection pool wait timeouts are each 600 seconds. These are per-phase timeouts for each attempt, not a total deadline including retries and waiting.
Pass a number of seconds, an
To limit the total duration of an asynchronous call or subscription, use
The application must manage the overall deadline for synchronous calls. For SSE, the read timeout limits the wait for the next chunk of data; it does not mean that the stream ends after 600 seconds in total.
List responses can be iterated across pages directly;
Use
Paginators preserve filters and request configuration. Not every collection endpoint is paginated; read
To read headers before deciding how to consume the response body, use
This controls how the HTTP response body is read and is a different interface from SSE event subscriptions. The asynchronous version uses
Pass an
Use
Installation
Requires Python 3.10 or later:
Basic usage
Save your personal access token (PAT) in an environment variable:
Client configuration
| Configuration | Forward | Managed |
|---|---|---|
| Synchronous client | Forward | Managed |
| Asynchronous client | AsyncForward | AsyncManaged |
| Base URL environment variable | QODER_FORWARD_BASE_URL | QODER_MANAGED_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 |
timeout and extend request configuration with extra_headers, extra_query, and extra_body. with_options(...) derives a client with different settings, such as a different retry count. It shares the connection pool with the original client; closing either closes that pool.
Authentication
PAT
Set your personal access token (PAT) with the pat parameter or the QODER_PAT environment variable.
Service Account
Set QODER_SA_KEY, then explicitly create a credential component. It exchanges and caches SATs (service account tokens), refreshing them when subsequent requests require it:
AsyncServiceAccountCredential with asynchronous clients:
Forward(auth_mode="sa", access_token=token); Managed and asynchronous clients accept the same configuration. The application is responsible for refreshing static SATs. Do not configure multiple credential sources at once. See the authentication documentation.
Asynchronous calls
Asynchronous clients use httpx.AsyncClient, with native asynchronous I/O for requests and response reads:
await the asynchronous function. Release connections with async with or await client.close(); avoid closing a client while requests are still pending.
Request and response types
Parameters and optional fields
Request parameters use TypedDict; nested parameters can be ordinary dictionaries. Forward and Managed types are in qca.forward.types and qca.managed.types, respectively.
| Parameter value | Request behavior |
|---|---|
Omit the parameter, or pass qca.NOT_GIVEN to a parameter that supports this sentinel | Omit the field |
None | Send JSON null |
False, 0, "" | Send as is |
| Empty list or dictionary | Send [] or {} |
null and how that value is handled are defined by the corresponding API.
Pydantic responses
Responses use Pydantic models. Read fields through attributes and serialize with to_dict() or to_json(). Unknown fields added by the server are preserved.
model_fields_set distinguishes a missing response field from a field explicitly returned as null. The default mode constructs responses using the expected model without requiring strict validation of every field; unexpected field values may retain their original types.
For strict response validation, pass _strict_response_validation=True when constructing the client. Responses that do not match the model raise APIResponseValidationError. Invalid JSON raises an error regardless of whether strict mode is enabled.
Streaming responses
Consume a single SSE connection with a context manager, which releases the connection on exit:
stream() ends at EOF. To continue subscribing after a recoverable disconnection, use resumable_stream():
resumable_stream() directly returns an object usable with async with; do not await its creation. Synchronous clients provide the same method name, used with with and a regular for loop.
A resumable stream reconnects with the SSE cursor of the most recently delivered event, without resending business requests. Without a cursor, it starts at the current tail of the event stream; reading history requires a valid historical resume position. Automatic reconnection does not guarantee exactly-once processing, and multiple deltas for one event may share an ID.
HTTP retry counts and the resumable stream reconnection lifecycle are controlled separately. Set an application-level deadline for persistent subscriptions and close the stream on early exit. Stream termination alone does not establish that a business task has completed; closing a stream or cancelling a local task does not automatically stop cloud execution.
Error handling and Request ID
Request errors inherit from qca.APIError. Distinguish timeouts, connection failures, HTTP errors, and response validation failures:
BadRequestError (400), AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404), ConflictError (409), and RateLimitError (429). Use APIStatusError to handle HTTP errors together.
Normal response models expose the request identifier through _request_id, and HTTP exceptions through request_id. It may be empty if the server does not return it. Asynchronous task cancellation follows the asyncio cancellation mechanism; after cleaning up resources, allow cancellation to propagate to the caller.
Retries and idempotency
By default, requests are retried up to 2 times, for a maximum of 3 attempts:
| Request | Retried by default for |
|---|---|
| GET, HEAD, or requests with an idempotency key | Connection errors, 408, 429, 5xx |
| Other requests without an idempotency key | 429 |
| 409 response | No automatic retries |
max_retries=0 when constructing a client to disable retries. Use client.with_options(max_retries=1) to adjust retries for a derived client. HTTP retry configuration does not automatically resume an established ordinary SSE connection; explicitly select a resumable stream.
Write methods that support idempotency keys provide an idempotency_key parameter. You can also pass the key through extra_headers={"Idempotency-Key": key}. Retries of the same logical operation must reuse the same key.
Timeouts and cancellation
The default connection timeout is 5 seconds. Read, write, and connection pool wait timeouts are each 600 seconds. These are per-phase timeouts for each attempt, not a total deadline including retries and waiting.
Pass a number of seconds, an httpx.Timeout, or None to disable timeouts:
asyncio.wait_for. The following function reuses read_resumable_events above:
Pagination
List responses can be iterated across pages directly; .data contains only the current page:
iter_pages() to process pages, or check has_next_page() before calling get_next_page(). Asynchronous clients support async for directly for pagination:
.data directly for unpaginated responses.
Advanced configuration
Raw responses and response body reads
with_raw_response returns the status code, response headers, and a parsable response body:
with_streaming_response and release the connection through a context manager:
async with and await response.parse().
Custom HTTP clients
Pass an httpx.Client or httpx.AsyncClient to configure proxies, TLS, transport, and connection pools:
extra_headers, extra_query, and extra_body to extend headers, query parameters, and the body. These settings can override fields set by the SDK, including authentication headers, so override only fields your application explicitly needs to adjust.