REST API reference
REST endpoints for persistent cloud browsers, connection grants, sharing, usage and billing.
Base URL & authentication
https://cloudbrowser.tv/api/v1
Authorization: Bearer <workspace_api_key>
Content-Type: application/jsonWorkspace keys authenticate management requests. Browser connection tokens do not authorize REST lifecycle or grant management. Viewer exchange, refresh and logout below use the isolated viewer origin and their own ticket/cookie authorization; never send a workspace key there. Browser access is checked on every request.
Operations
POST/browsers
Create a browser
Reserves a concurrent slot atomically. Returns an operation; connection grants require running status.
cloudbrowser create --name research --waitBody schema: CreateBrowser. See schema definitions below.
Success: 202. Complete parameters and response schema ↗
GET/browsers
List browsers
Authenticated, workspace-scoped operation.
cloudbrowser list --output jsonSuccess: 200. Complete parameters and response schema ↗
GET/browsers/{browserId}
Get a browser
Authenticated, workspace-scoped operation.
cloudbrowser get br_123Success: 200. Complete parameters and response schema ↗
DELETE/browsers/{browserId}
Delete a browser
Revoke all grants and stop connections. Deletion is terminal.
cloudbrowser delete br_123 --yesSuccess: 202. Complete parameters and response schema ↗
POST/browsers/{browserId}/pause
Pause a browser
Disconnect transports on pause. Resume checks quota and requires fresh CDP grants or new viewer sessions obtained through existing share URLs. Profile persists; live page memory is not guaranteed. Pause/runtime replacement ends viewer sessions and outstanding tickets and invalidates CDP grants; reusable Live View shares remain configured. After resume, reopen the same share URL for a new runtime-bound session. No implicit resume for viewers. Application pause first asks Chrome to exit gracefully and waits for its supervisor restart to confirm profile flush. If shutdown cannot be confirmed, the operation fails before submitting provider pause. This is distinct from provider TTL expiry.
cloudbrowser pause br_123 --waitSuccess: 202. Complete parameters and response schema ↗
POST/browsers/{browserId}/resume
Resume a browser
Disconnect transports on pause. Resume checks quota and requires fresh CDP grants or new viewer sessions obtained through existing share URLs. Profile persists; live page memory is not guaranteed. Pause/runtime replacement ends viewer sessions and outstanding tickets and invalidates CDP grants; reusable Live View shares remain configured. After resume, reopen the same share URL for a new runtime-bound session. No implicit resume for viewers.
cloudbrowser resume br_123 --waitSuccess: 202. Complete parameters and response schema ↗
POST/browsers/{browserId}/fork
Fork a browser
Create independent browser ID and profile from a consistent snapshot. No access grants are inherited. Snapshot consistency must be qualified before implementation ships. The source must be paused; a running source returns 409 pause_required. Paused-source inheritance and independent writes passed the live test. Never treat a failed operation as a successful child snapshot.
cloudbrowser fork br_123 --name research-copy --waitBody schema: ForkBrowser. See schema definitions below.
Success: 202. Complete parameters and response schema ↗
POST/browsers/{browserId}/grants
Create connection access
Create CDP access or a Live View link. Live View defaults to a reusable share URL, read-only permission and no expiration. A short-lived one-time ticket is a separate session-entry credential. Share visits may create multiple independent viewer sessions; CLI exits after returning/opening the URL. Browser must be running when creating/using entry tickets. Draft only.
cloudbrowser connect br_123 --audience cdp --ttl 1h --output jsonBody schema: CreateGrant. See schema definitions below.
Success: 201. Complete parameters and response schema ↗
GET/browsers/{browserId}/grants
List access grants
List metadata only, never bearer URLs, share secrets, refresh cookies or entry tickets. Live View metadata includes permission, expiresAt (null for never), lastOpenedAt, activeSessions and revision. Filter by audience/status; paginate with cursor/limit. Local implementation returns all matching entries with nextCursor=null; pagination is pending.
cloudbrowser tokens list br_123Success: 200. Complete parameters and response schema ↗
POST/browsers/{browserId}/grants/{grantId}/renew
Renew a grant lease
CDP ONLY; reject live-view audience with 400 audience_not_supported. Requires workspace authorization, active renewable CDP grant and unchanged runtime. Extend expiresAt to min(now + original TTL, renewUntil), keeping opaque token stable. No hard-stop or privilege expansion. Expired/revoked CDP grants cannot renew. Viewer sessions instead use the viewer refresh endpoint and their own refresh cookie.
cloudbrowser tokens renew br_123 grant_123Success: 200. Complete parameters and response schema ↗
DELETE/browsers/{browserId}/grants/{grantId}
Revoke access
Permanently revoke this grant, close its streams, and invalidate all tickets and refresh families. Reusable URL can no longer create sessions. Idempotent; revoked grants cannot be revived. Does not delete the browser.
cloudbrowser tokens revoke br_123 grant_123 --yesSuccess: 200. Complete parameters and response schema ↗
PATCH/browsers/{browserId}/grants/{grantId}
Change a Live View share link policy
Share-mode Live View only. At least one property required. Every effective policy change invalidates all old sessions and tickets immediately and increments revision. The same reusable URL can then open a fresh session. Revoked grants cannot be revived. An expired share may be extended by its owner, but previous sessions stay ended. Gateway immediately closes old streams and rejects all old refresh credentials and input frames. Read-only to control changes also require a fresh session, so a refresh cannot silently gain write permission. Check workspace ownership and authorization on every update. No changes to CDP grants through this endpoint.
cloudbrowser links update br_123 grant_123 --permission view --expires-in 24hBody schema: UpdateLiveViewGrant. See schema definitions below.
Success: 200. Complete parameters and response schema ↗
GET/operations/{operationId}
Inspect an operation
Authenticated, workspace-scoped operation.
cloudbrowser operations get op_123Success: 200. Complete parameters and response schema ↗
GET/usage
Get current usage
Authenticated, workspace-scoped operation.
cloudbrowser usage --output jsonSuccess: 200. Complete parameters and response schema ↗
POST/b/{browserId}/session/exchange
Exchange a Live View link
Exchange a short-lived viewer ticket minted through account/library authorization. Atomically consume once, checking recipient account binding, browser, current grant revision, permission and runtime. The viewer never receives the main account cookie or a workspace API key. Reusable sharing acceptance happens on cloudbrowser.tv, not by anonymous viewer redemption. Atomically consume the ticket once before ticketExpiresAt. Check browser, current grant revision and runtime. Link expiresAt is a separate authorization deadline (null means no absolute deadline). Issue a 5-minute access cookie and, for autoRenew=true, a rotating refresh cookie with a 30-minute inactivity deadline, both capped by expiresAt when finite. For autoRenew=false, no refresh cookie and idle/access expiration is 5 minutes capped by expiresAt. Ticket expiry after exchange does not end the session. A reusable share may create multiple recipient sessions; each ticket is single-use. Cookie secrets never appear in JSON. A paused browser cannot exchange tickets and must not be implicitly resumed. Use isolated viewer origin, no-store/no-referrer, strict CSP, same-origin credentials, exact Origin/CSRF checks and redacted logs. Check current link authorization, permission, revision, runtime and issuer access on every request and stream. Never accept a workspace API key here. Local cookies are independently named per viewer session (cb_access_{sessionId}, cb_refresh_{sessionId}) and omit Secure on localhost HTTP. No anonymous account authorization.
fetch("/b/br_123/session/exchange", {
method: "POST",
credentials: "same-origin",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ticket }), // received from the account shell via a validated handshake
});
// Runs on https://view.cloudbrowser.tv; cookies are set by the server.
// No CLI process or workspace API key required.Body schema: ExchangeViewerTicket. See schema definitions below.
Success: 200. Complete parameters and response schema ↗
POST/b/{browserId}/session/refresh
Refresh the viewer session
Use the rotating refresh cookie even if access has expired. No CLI or workspace credential required. Reject ended/revoked sessions, inactive links, changed revisions/runtimes or expired idle deadline. Refresh is allowed indefinitely for actively used links with expiresAt=null. For finite expiresAt, stop all access when the next authorization check observes the deadline, including existing streams. Rotate atomically with reuse detection; serialize refresh across same-browser tabs. Access expiry=min(now+5 minutes, link expiresAt when finite); idle expiry=min(now+30 minutes, finite link deadline). Successful refresh reauthorizes existing same-session streams without page reload. Do not extend the link deadline or widen permissions. After inactivity, reopen the saved browser through account/library authorization to establish a new session. Use isolated viewer origin, no-store/no-referrer, strict CSP, same-origin credentials, exact Origin/CSRF checks and redacted logs. Check current link authorization, permission, revision, runtime and issuer access on every request and stream. Never accept a workspace API key here. Validate the recipient’s active account/membership as well as the owner’s source grant. Removal from the recipient library invalidates that recipient’s sessions only. Local cookies are independently named per viewer session (cb_access_{sessionId}, cb_refresh_{sessionId}) and omit Secure on localhost HTTP. No anonymous account authorization.
fetch("/b/br_123/session/refresh", {
method: "POST",
credentials: "same-origin",
});
// Runs on https://view.cloudbrowser.tv; cookies are set by the server.
// No CLI process or workspace API key required.Success: 200. Complete parameters and response schema ↗
POST/b/{browserId}/session/logout
End the viewer session
End only the current viewer session, revoke its refresh family and close streams; clear cookies using the exact browser-specific path. Does not revoke the share URL: the accepted account can reopen its saved browser for a new session. Direct one-time tickets remain consumed. Missing/expired cookies are cleared and return 200. Closing a page alone is not reliable logout. Use isolated viewer origin, no-store/no-referrer, strict CSP, same-origin credentials, exact Origin/CSRF checks and redacted logs. Check current link authorization, permission, revision, runtime and issuer access on every request and stream. Never accept a workspace API key here. Validate the recipient’s active account/membership as well as the owner’s source grant. Removal from the recipient library invalidates that recipient’s sessions only. Local cookies are independently named per viewer session (cb_access_{sessionId}, cb_refresh_{sessionId}) and omit Secure on localhost HTTP. No anonymous account authorization.
fetch("/b/br_123/session/logout", {
method: "POST",
credentials: "same-origin",
});
// Runs on https://view.cloudbrowser.tv; cookies are set by the server.
// No CLI process or workspace API key required.Success: 200. Complete parameters and response schema ↗
GET/browsers/{browserId}/grants/{grantId}/sessions
List a link’s authorized viewer sessions
Workspace authorization required. Return metadata only; no cookies, tokens or private page content. Expired/ended sessions are excluded. Local implementation returns all matching entries with nextCursor=null; pagination is pending.
cloudbrowser links sessions br_123 grant_123Success: 200. Complete parameters and response schema ↗
DELETE/browsers/{browserId}/grants/{grantId}/sessions
End all sessions for a Live View link
Workspace authorization required. Invalidate all current sessions, refresh families and outstanding entry tickets; close streams. The reusable share URL stays valid for future visits. Use revokeGrant to prevent future visits too. Does not operate on CDP.
cloudbrowser links end-sessions br_123 grant_123 --yesSuccess: 200. Complete parameters and response schema ↗
GET/library/browsers
List my owned and shared browsers
Signed-in account only. Owned and shared entries appear in one grid. A shared entry does not transfer ownership, create a browser, consume the recipient’s browser concurrency, or grant lifecycle/reshare/CDP rights. Every preview subscription rechecks current authorization. Unavailable entries may remain visible without streaming private contents. Compute remains on the owning workspace. Local implementation returns all matching entries with nextCursor=null; pagination is pending.
cloudbrowser library list --source all --output jsonSuccess: 200. Complete parameters and response schema ↗
POST/library/browsers/{browserId}/viewer-ticket
Open an owned or saved shared browser
Account authorization required. Check ownership or saved membership AND its current parent grant permission, revision, expiration and issuer access; a saved list entry is not authority by itself. Browser must be running to stream; paused view shows an explicitly labeled authorized last frame without implicitly resuming. Mint a short-lived one-use runtime-bound ticket for the isolated viewer origin. The account shell passes only this ticket through a strict origin-checked handshake to the viewer, never its account cookie or workspace API key. Shared control grants no lifecycle, deletion, fork, reshare or CDP rights. Grid and fullscreen use this same authorization path; switching presentation alone does not duplicate runtime sessions.
cloudbrowser library view br_sharedSuccess: 201. Complete parameters and response schema ↗
GET/billing/status
Get plan, runtime, estimated overage and billing access
Only the workspace billing owner can modify billing.
See CLI referenceSuccess: 200. Complete parameters and response schema ↗
POST/billing/checkout
Start hosted Stripe Checkout for a new subscription
Only the workspace billing owner can modify billing. Additional usage is charged separately at period close. Monthly amount and extra hourly rate appear in Checkout.
See CLI referenceBody schema: CheckoutRequest. See schema definitions below.
Success: 200. Complete parameters and response schema ↗
POST/billing/portal
Open payment methods and invoices
Only the workspace billing owner can modify billing.
See CLI referenceSuccess: 200. Complete parameters and response schema ↗
POST/billing/refresh
Reconcile Stripe payment and subscription status
Only the workspace billing owner can modify billing.
See CLI referenceSuccess: 200. Complete parameters and response schema ↗
POST/billing/upgrade-preview
Preview Basic to Pro proration; valid for five minutes
Only the workspace billing owner can modify billing.
See CLI referenceSuccess: 200. Complete parameters and response schema ↗
POST/billing/plan
Upgrade after payment or schedule downgrade/cancel for next period
Only the workspace billing owner can modify billing.
See CLI referenceBody schema: PlanChangeRequest. See schema definitions below.
Success: 200. Complete parameters and response schema ↗
Request and response schemas
CreateBrowser
{
"type": "object",
"required": [
"name"
],
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 50
}
}
}ForkBrowser
{
"type": "object",
"required": [
"name"
],
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 50
},
"startPaused": {
"type": "boolean",
"default": true,
"description": "Paused forks do not reserve running capacity. They retain independent profile writes."
}
}
}CreateGrant
{
"oneOf": [
{
"$ref": "#/components/schemas/CreateCdpGrant"
},
{
"$ref": "#/components/schemas/CreateLiveViewGrant"
}
],
"discriminator": {
"propertyName": "audience",
"mapping": {
"cdp": "#/components/schemas/CreateCdpGrant",
"live-view": "#/components/schemas/CreateLiveViewGrant"
}
}
}CreateCdpGrant
{
"type": "object",
"required": [
"audience"
],
"additionalProperties": false,
"properties": {
"audience": {
"const": "cdp"
},
"permission": {
"const": "control"
},
"ttlSeconds": {
"type": "integer",
"minimum": 300,
"maximum": 86400,
"default": 3600
},
"autoRenew": {
"type": "boolean",
"default": false,
"description": "CDP only. Authenticated CLI/console manager performs renewal; the CDP client cannot refresh itself."
},
"renewUntil": {
"type": "string",
"format": "date-time",
"description": "Required for autoRenew; must be at least initial expiry and at most 7 days after issue. Immutable hard stop."
}
},
"allOf": [
{
"if": {
"properties": {
"autoRenew": {
"const": true
}
},
"required": [
"autoRenew"
]
},
"then": {
"required": [
"renewUntil"
]
}
}
]
}CreateLiveViewGrant
{
"type": "object",
"additionalProperties": false,
"properties": {
"audience": {
"const": "live-view"
},
"mode": {
"type": "string",
"enum": [
"share",
"one-time"
],
"default": "share",
"description": "share returns a reusable bearer URL. one-time returns a ticket URL redeemable once."
},
"permission": {
"type": "string",
"enum": [
"view",
"control"
],
"default": "view",
"description": "view is read-only: stream only, no mouse, keyboard, touch, clipboard writes, uploads, navigation commands or browser control. control allows browser interaction but no workspace, lifecycle or CDP administration. Enforced by the gateway, not just UI."
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time",
"default": null,
"description": "Absolute link authorization deadline, measured from issuance/update; null means no expiration. Applies to new visits AND all existing sessions. Automatic refresh never moves this deadline."
},
"ticketTtlSeconds": {
"type": "integer",
"minimum": 60,
"maximum": 900,
"default": 300,
"description": "One-time ticket lifetime, independent of the link authorization deadline. Shared links mint fresh tickets on each visit. Direct one-time links mint a ticket at issuance."
},
"autoRenew": {
"type": "boolean",
"default": true,
"description": "Viewer webpage refreshes short-lived credentials while link authorization remains valid; no fixed maximum when expiresAt is null. If false, access lasts 5 minutes or until expiresAt, whichever comes first, with no refresh cookie."
}
},
"required": [
"audience"
]
}UpdateLiveViewGrant
{
"type": "object",
"additionalProperties": false,
"properties": {
"permission": {
"type": "string",
"enum": [
"view",
"control"
],
"default": "view",
"description": "view is read-only: stream only, no mouse, keyboard, touch, clipboard writes, uploads, navigation commands or browser control. control allows browser interaction but no workspace, lifecycle or CDP administration. Enforced by the gateway, not just UI."
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time",
"default": null,
"description": "Absolute link authorization deadline, measured from issuance/update; null means no expiration. Applies to new visits AND all existing sessions. Automatic refresh never moves this deadline."
}
},
"required": [],
"minProperties": 1,
"description": "Share-mode Live View only. At least one property required. Every effective policy change invalidates all old sessions and tickets immediately and increments revision. The same reusable URL can then open a fresh session. Revoked grants cannot be revived. An expired share may be extended by its owner, but previous sessions stay ended."
}AcceptSharedBrowser
{
"type": "object",
"additionalProperties": false,
"properties": {
"linkId": {
"type": "string"
},
"shareToken": {
"type": "string"
},
"ticket": {
"type": "string"
}
},
"required": [
"linkId"
],
"oneOf": [
{
"required": [
"shareToken"
],
"not": {
"required": [
"ticket"
]
}
},
{
"required": [
"ticket"
],
"not": {
"required": [
"shareToken"
]
}
}
],
"description": "Account authorization plus one invitation credential. Token read from URL fragment and removed immediately. Store a server-side pending authorization handle bound to the login transaction when redirecting to sign-in; never put the bearer secret in OAuth state, returnTo, query strings, analytics or localStorage."
}BrowserLibraryEntry
{
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "br_123"
},
"name": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"starting",
"running",
"pausing",
"paused",
"resuming",
"failed",
"deleting",
"unavailable"
]
},
"parentId": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"error": {
"type": [
"string",
"null"
]
},
"runtimeGeneration": {
"type": "integer"
},
"owner": {
"type": "boolean"
},
"permission": {
"type": "string",
"enum": [
"view",
"control"
]
},
"ownerName": {
"type": "string"
},
"shared": {
"type": "boolean",
"description": "Owned browser has at least one currently active sharing grant."
}
},
"required": [
"id",
"name",
"status",
"owner",
"permission",
"runtimeGeneration"
]
}ViewerTicket
{
"type": "object",
"additionalProperties": false,
"properties": {
"ticket": {
"type": "string",
"description": "One-time secret minted after account/library authorization, bound to recipient account, browser, grant revision, permission and runtime. Return only on ticket issuance."
},
"ticketExpiresAt": {
"type": "string",
"format": "date-time"
},
"url": {
"type": "string",
"description": "Isolated viewer URL carrying a single-use ticket in its fragment. The viewer clears the fragment before exchange."
}
},
"required": [
"ticket",
"ticketExpiresAt",
"url"
]
}ExchangeViewerTicket
{
"type": "object",
"additionalProperties": false,
"required": [
"ticket"
],
"properties": {
"ticket": {
"type": "string",
"description": "Single-use opaque secret from the URL fragment. Never log it."
}
}
}GrantIssue
{
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"required": [
"grant",
"cdpUrl"
],
"properties": {
"grant": {
"$ref": "#/components/schemas/CdpGrant"
},
"cdpUrl": {
"type": "string",
"description": "Secret returned only on issuance."
}
}
},
{
"type": "object",
"required": [
"grant",
"liveViewUrl"
],
"properties": {
"grant": {
"$ref": "#/components/schemas/LiveViewGrant"
},
"liveViewUrl": {
"type": "string",
"description": "Public account-shell entry URL, returned only at issuance: https://cloudbrowser.tv/view/{grantId}#share=... (reusable) or #ticket=... (one-time invitation). Sign in and accept into your library, then open /browsers/{browserId} fullscreen in the same workspace. Viewer transport remains isolated at view.cloudbrowser.tv. Raw secrets never appear in listings."
}
}
}
]
}LiveViewGrant
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"browserId": {
"type": "string"
},
"audience": {
"const": "live-view"
},
"mode": {
"type": "string",
"enum": [
"share",
"one-time"
]
},
"permission": {
"type": "string",
"enum": [
"view",
"control"
],
"default": "view",
"description": "view is read-only: stream only, no mouse, keyboard, touch, clipboard writes, uploads, navigation commands or browser control. control allows browser interaction but no workspace, lifecycle or CDP administration. Enforced by the gateway, not just UI."
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time",
"default": null,
"description": "Absolute link authorization deadline, measured from issuance/update; null means no expiration. Applies to new visits AND all existing sessions. Automatic refresh never moves this deadline."
},
"ticketTtlSeconds": {
"type": "integer"
},
"entryExpiresAt": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "Direct one-time URL only; null for reusable shares."
},
"autoRenew": {
"type": "boolean"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"lastOpenedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"activeSessions": {
"type": "integer",
"minimum": 0,
"description": "Current authorized viewer sessions, not connected socket count."
},
"revision": {
"type": "integer",
"minimum": 1
},
"status": {
"type": "string",
"enum": [
"active",
"expired",
"revoked",
"used"
]
},
"revoked": {
"type": "boolean"
}
},
"required": [
"id",
"browserId",
"audience",
"mode",
"permission",
"expiresAt",
"ticketTtlSeconds",
"entryExpiresAt",
"autoRenew",
"createdAt",
"lastOpenedAt",
"activeSessions",
"revision",
"status",
"revoked"
]
}ViewerSession
{
"type": "object",
"additionalProperties": false,
"required": [
"id",
"grantId",
"browserId",
"permission",
"autoRenew",
"accessExpiresAt",
"idleExpiresAt",
"ended",
"authorizationExpiresAt",
"accountId"
],
"properties": {
"id": {
"type": "string"
},
"grantId": {
"type": "string"
},
"browserId": {
"type": "string"
},
"permission": {
"type": "string",
"enum": [
"view",
"control"
],
"default": "view",
"description": "view is read-only: stream only, no mouse, keyboard, touch, clipboard writes, uploads, navigation commands or browser control. control allows browser interaction but no workspace, lifecycle or CDP administration. Enforced by the gateway, not just UI."
},
"autoRenew": {
"type": "boolean"
},
"accessExpiresAt": {
"type": "string",
"format": "date-time"
},
"idleExpiresAt": {
"type": "string",
"format": "date-time"
},
"ended": {
"type": "boolean"
},
"authorizationExpiresAt": {
"type": [
"string",
"null"
],
"format": "date-time",
"default": null,
"description": "Absolute link authorization deadline, measured from issuance/update; null means no expiration. Applies to new visits AND all existing sessions. Automatic refresh never moves this deadline."
},
"accountId": {
"type": "string",
"description": "Recipient account binding; never infer identity from browserId alone."
}
}
}Errors, pagination and retries
Errors return code, message and requestId. Lists accept an opaque cursor and limit (1–100), and return items and nextCursor.
| Status | Meaning |
|---|---|
| 400 | Invalid parameters or token policy. |
| 401 / 403 | Missing credentials or insufficient access. |
| 404 | Resource not found or not visible to this caller. |
| 409 | Lifecycle conflict, expired/revoked grant, idempotency conflict. |
| 410 | Viewer entry ticket is expired, invalid or already consumed. |
| 429 | Concurrency or rate limit; include Retry-After when applicable. |
| 503 | Runtime temporarily unavailable. |
Create and fork require Idempotency-Key. Retry with the original key and identical payload after an uncertain response. Never infer that a timeout means no resource was created.