System One
System One
DocumentationSDK documentationModelsAPI referenceOpen System OneDocumentation index

SDK & API

API referenceAPI versioningIdempotency keysAPI error codes

Build with decisions

Choose a modelDecision primitivesAgent integration: typed tool routingSystem One for coding agents (Claude Code, Cursor, Codex)

Usage & data

Billing and creditsPrivacy and zero data retention
API reference

Idempotency keys

Send idempotency keys with System One API requests to safely retry decisions without double-charging.

New logical operation → new random UUID. Retry or recovery of the same operation → the same saved key and complete request. Intentionally evaluating identical input again is a new operation, not a retry. An operation key lets an HTTP or SDK client recover a successful result after a lost response without another evaluation or charge, within the retention window. These rules apply to the hosted API and session Playground, not universally to standalone SDK adapters or direct providers.

Answer-ready

Q: What is an idempotency key in the System One API?
A: An idempotency key is a client-generated token you send with a System One API request so retries return the same decision result and do not double-charge credits.

Q: When should I send an idempotency key?
A: Send one whenever your client may retry the same logical decision after timeouts, network errors, or 5xx responses.

Save one key per operation

Send an Idempotency-Key header for each operation. Create its UUID once, before the first send, and keep it with the complete request. Do not use a global environment key, a constant shared by jobs, or a content hash: identical content can belong to separate billable evaluations. Keys are 1–128 characters, start with a letter or digit, and then allow letters, digits, dots, underscores, colons, and hyphens.

ScenarioOperation key and request
New decision or new jobCreate a fresh UUID and a complete request.
Intentionally evaluate the same input againCreate a fresh UUID, even though the request body is identical; this is a new billable operation.
Retry after timeout, lost response, or request_in_progressReuse the existing operation's key and unchanged complete request; respect any retry delay.
Recover after an application crash or restartLoad the whole operation durably saved before the first send; do not rerun operation creation.
Use another API key for the same accountKeep the same operation key for recovery; changing credentials does not create a separate namespace.

For a retry, use the same operation object created in the hosted quickstart. This snippet replaces its evaluate() call and reuses its client; it does not create an operation or generate a UUID:

const result = await client.evaluate(operation.request, {
  maxRetries: 0,
  timeoutMs: 30_000,
  headers: { 'Idempotency-Key': operation.idempotencyKey },
});

The quickstart keeps the operation only in memory. Every script run creates a new billable operation, not restart-safe recovery. In a real application, durably save the whole operation—its key and complete request, including the selected model—in the application's job record before the first send. After a crash, load that record instead of creating a UUID or rebuilding the request. For an in-process retry, keep the existing object and rerun only the call after handling the recorded outcome below. Do not generate a fresh key inside retry code: it can create another charge.

The HTTP reference shows the equivalent header in a curl request. Neither the SDK nor its Fetch transport creates an idempotency key automatically.

Keep the request unchanged

Keys are scoped to an account, across all of its API keys and its session Playground. Other accounts have separate namespaces. A different valid API key for the same account can recover an operation; a revoked key cannot authenticate it. API keys do not acquire permission to call session-only endpoints.

The service compares the validated canonical request, including its effective model, context, questions, criteria, and accepted extension fields. Formatting whitespace and object-key order do not matter. Array order, score-rubric order, field values, and null versus omitted fields do matter. A different request under the same key returns 409 idempotency_conflict.

Always send and save an explicit model ID from the current models list. An omitted model is resolved to the service default before comparison. Explicit aliases and version names remain part of the request identity, even if two names resolve to the same model. Do not replace the requested ID with the response's resolved model while recovering. If a previous request omitted its model, retain the original effective model when the default changes; inspect the original operation before attempting recovery.

Exact decimal identity is preserved: 9007199254740993 differs from 9007199254740992, and 1e-400 differs from zero. Equivalent decimal spellings compare equally, and duplicate object keys are rejected, including escaped equivalent names. This compares the JSON submitted on the wire; it cannot restore precision already lost in your client's numeric type. Preserve original JSON text when required. A different model or rubric is a new operation and can have a different price; a successful replay of the original still charges zero.

Images are part of the complete request identity, including every base64 string, media type, representation and array order. Reordering or replacing an image under the same retained key conflicts; changing between a data URL and an object is not a transparent retry. images: [] is valid for text-only models but is not identical to omitting the field. Keep the original body for recovery rather than re-encoding files or rebuilding it from the current Playground state.

Follow the recorded outcome

Existing operationResponse to the same key and bodyWhat to do
No retained operationA new evaluation can begin and charge credits.Keep the key until the outcome is known.
Still processing409 request_in_progress, with Retry-After: 2.Wait, then retry the same key and body.
SucceededReturns the saved response status, text, and allowed headers without another evaluation or charge.Use the recovered result.
Failed and credits returned409 idempotency_failed.Use a new key only for a deliberate new attempt.
Body differs409 idempotency_conflict.Restore the original body, or assign a new key to a genuinely different operation.
Answer no longer available410 idempotency_expired.Check the original operation before starting another.

A successful replay includes X-Idempotency-Replayed: true, X-System-One-Credits: 0, and the original X-Request-Id, retaining original model-service tracking headers when available. It reuses the saved response rather than reevaluating the model, re-rounding values, or adding System One replayed, billing, or request_id fields to the body. Any model-supplied fields with those names are not System One accounting. Do not compare two independent evaluations to test replay fidelity: a new operation can produce a different answer.

Replay attempts still count toward the account's decision rate limit. The new attempt has current account rate-limit headers, so not every HTTP header is identical to the original. Responses use Cache-Control: no-store; ordinary browser or proxy caching is not the idempotency mechanism.

The 24-hour window

Completed operations can be recovered using their keys for 24 hours from request creation. After that window, the same key can start a new billable operation; it may not return an expired-key error. This is not permanent duplicate protection.

Without an operation key, repeating a request is a separate evaluation. Save important answers in your own application rather than relying on replay as long-term access to results.

An ordinary failed evaluation returns its reserved credits before the error response. An interruption can leave an operation pending; requests pending for more than 15 minutes become eligible for reconciliation, but this is not an immediate completion or refund deadline. Keep the original key and request ID until the outcome is known. An unsettled pending operation is not permission to create a replacement after 24 hours: the retention window is not a promise to clear an in-flight operation.

If a request returns 503 request_reconciliation_pending, its charge is not yet settled. X-System-One-Credits is omitted; missing does not mean zero. Recovery may not be immediate. Keep the original key and X-Request-Id, check console usage, and contact support@system-one.dev if the outcome remains unclear. Do not switch to a new key just to get past the error.

SDK retry settings

The SDK example disables automatic retries with maxRetries: 0 so the application can follow the outcome table. The SDK's retry policy can retry network errors and selected HTTP failures, but it does not automatically resolve the different 409 states. Enabling retries still requires the same saved key and body; disabling retries does not cancel a server operation whose response was lost. The service does not automatically retry model inference.

Core APIError exposes statusCode, requestId, and retryAfterMs, but not the full body or classification headers. Use Fetch to read X-System-One-Error-Code when distinguishing conflict, pending, and failed states. Follow Retry-After, which may be seconds or an HTTP date. Check X-System-One-Error-Source: a model-service 401 does not mean your System One login expired. See the error reference.

The separate official TypeSafe client has its own retry settings and also needs an explicitly retained idempotency key when calling this service. The standalone SDK's direct-provider adapters follow their own service contracts; do not infer hosted credit or replay semantics from an SDK package version.

API versioning

How System One versions the decision API and which headers to send from the TypeScript SDK.

API error codes

System One API error shapes, status codes, and how to handle failures in the TypeScript SDK.

On this page

Answer-readySave one key per operationKeep the request unchangedFollow the recorded outcomeThe 24-hour windowSDK retry settings