typeship APIAPI

Idempotent writes

Retry accepted writes without duplicating resources, generation work, or repository effects.

Send an Idempotency-Key on a retry-sensitive write. If the connection drops after Typeship accepts the request, retry the same operation with the same key and inputs. The API returns the first completed response without running the work again.

curl -sS https://typeship.dev/api/v1/projects/prj_.../generations \
  -X POST \
  -H "Authorization: Bearer $TYPESHIP_TOKEN" \
  -H "Idempotency-Key: deploy-acme-2026-09-02"

The TypeScript, Python, and Go SDKs generate a key when you omit one and keep it stable across the call's transport retries. Pass your own key when the logical write must survive a process restart. The typeship CLI exposes --idempotency-key, and typeship MCP tool schemas expose the same optional Idempotency-Key input.

Replay contract

  • A key is scoped to one authenticated account and operation. Anonymous POST /generate uses a hashed network identity as its account-less scope.
  • The request identity includes the HTTP method, path parameters, query parameters, and JSON body. JSON object order and query-name order do not matter; array and repeated-query-value order do.
  • Identical concurrent requests wait on one reservation and converge on its response.
  • A replay does not consume the operation's rate-limit budget again or get replaced by a later rate-limit response.
  • Idempotency-Replayed: false marks the first completed response. A replay returns Idempotency-Replayed: true with the original status, semantic body, and contract-relevant headers. The replay receives a fresh request_id so its own HTTP attempt remains traceable.
  • Reusing a key with a changed path, query, or body returns 409 idempotency_key_reused and does not run the new intent.
  • If the first request is still running beyond the request wait window, the API returns retryable 429 rate_limited with Retry-After. Retry the same request and key.

Completed responses and deterministic client or precondition failures are retained for 24 hours. 408, 425, 429, server failures, and interrupted executions release their reservation so a later attempt can run. Expired rows are removed as new keyed writes arrive. After 24 hours, reusing a key starts a new logical write, so do not rely on it for permanent resource identity.

Authentication and authorization run before the account-scoped replay lookup. Fix 401 or 403 responses rather than retrying them as an idempotent write.

Public write decisions

The checked-in source for this audit is openapi/idempotency-matrix.json. Replay store means the operation accepts Idempotency-Key. Natural means repeating the method can change the response, but cannot repeat the resource or external side effect.

OperationWriteDecisionWhy
runPOST /generateReplay storeGeneration consumes rate-limited compute even though no durable result is retained.
createProjectPOST /projectsReplay storeCreates a Project, Definition, initial Targets, and first revision.
updateProjectPATCH /projects/{project_id}NaturalReplaces stored desired-state fields and starts no generation or delivery.
deleteProjectDELETE /projects/{project_id}NaturalConverges on absence without an external side effect.
updateDefinitionPATCH /definitions/{definition_id}Replay storeResolves external source input and may record a new immutable revision.
refreshProjectDiagnosticsPOST /projects/{project_id}/diagnosticsReplay storeFetches the source and may record a new immutable revision.
remediateProjectDiagnosticsPOST /projects/{project_id}/diagnostics/remediationsReplay storeChanges overlays or creates or updates a source review.
createTargetPOST /projects/{project_id}/targetsReplay storePersists a separately metered Target and its Deliveries.
updateTargetPATCH /targets/{target_id}NaturalReplaces Target and Delivery desired state; generation owns repository effects.
deleteTargetDELETE /targets/{target_id}NaturalIs allowed only without Generation or release dependencies and converges on absence.
generateProjectPOST /projects/{project_id}/generationsReplay storePersists Generations, consumes metered work, and may update repository reviews.
revokeApiKeyDELETE /api_keys/{api_key_id}NaturalConverges on one revoked state and already returns the same representation.

For a replay-store operation, omitting the header starts an ordinary unprotected write. Do not retry an accepted write after a timeout unless your SDK supplied a key or you supplied one yourself.

On this page