openapi: 3.1.0
info:
title: durable-actors HTTP API
version: "1"
description: |
Manage durable-actors deployments, invoke actors, find actor hosts, and inspect activity.
When DURABLE_ACTORS_SECRET is set on the server, authenticate backend requests
with that bearer API key; never expose it to browsers. When unset, no API key is required.
Project-scoped actor routes work in development and production. Run `durable-actors dev`
and copy the printed connection settings into your backend's environment. The default
local project ID is `local`; use it as `project_id` in requests.
Servers listening beyond localhost warn when the secret is unset but still start.
servers:
- url: http://127.0.0.1:7100
description: Local server.
security:
- ApiKey: []
- {}
tags:
- name: Discovery
- name: Deployments
- name: Actors
- name: Observability
- name: WebSockets
- name: Sessions
paths:
/openapi.yaml:
get:
operationId: getOpenApi
tags: [Discovery]
summary: Get the API specification
security: []
responses:
"200":
description: OpenAPI 3.1 document.
content:
application/yaml:
schema: { type: string }
/healthz:
get:
operationId: getHealth
tags: [Discovery]
summary: Check server health
security: []
responses:
"200":
description: Server is running.
content:
text/plain:
schema: { type: string, const: ok }
/v1/projects/{project_id}/deployment:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
put:
operationId: registerDeployment
tags: [Deployments]
summary: Deploy actors
description: Registers a compiled GCS bundle and its actor contract. Build and upload with any compatible toolchain before calling this endpoint. Replaces the deployment and restarts actors while preserving saved state. The bundle must use the configured artifact bucket and durable-actors/v3/artifacts/{UUID}/ paths. A new bundle requires contract; resubmitting the current bundle may omit it to retain the current contract. Local development registers localSource with its project directory and entrypoint.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/Deployment" }
examples:
compiled:
value:
bundle:
bucket: actor-code
files:
- path: actors.mjs
object: durable-actors/v3/artifacts/00000000-0000-4000-8000-000000000001/actors.mjs
generation: 123456789
sha256: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
contract: { version: 1, actors: [], typescript: { declarations: "export interface ActorTypes {}", dependencies: {} } }
local:
value:
localSource: { workingDirectory: /project, actorEntrypoint: src/actors.ts }
responses:
"200": { $ref: "#/components/responses/Changed" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
get:
operationId: getDeployment
tags: [Deployments]
summary: Get current deployment
responses:
"200":
description: Active deployment, without the contract.
content:
application/json:
schema: { $ref: "#/components/schemas/CurrentDeployment" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"404": { $ref: "#/components/responses/NotFound" }
"500": { $ref: "#/components/responses/Internal" }
delete:
operationId: deleteDeployment
tags: [Deployments]
summary: Delete deployment
description: Stops deployed actors and keeps their saved state.
responses:
"200": { $ref: "#/components/responses/Changed" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/deployment/contract:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: getContract
tags: [Deployments]
summary: Get actor contracts
responses:
"200":
description: Active actor contract.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema:
type: object
required: [contractHash, contract]
properties:
contractHash:
type: string
pattern: "^sha256:[a-f0-9]{64}$"
description: Contract fingerprint.
contract: { $ref: "#/components/schemas/PublicActorContract" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"404": { $ref: "#/components/responses/NotFound" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/sessions:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
post:
operationId: issueActorSession
tags: [Sessions]
summary: Issue a scoped RPC session
security: [{ ApiKey: [] }]
description: Requires the configured administrative secret and an active deployment. The trusted backend must authenticate its caller and check project ACLs first. Sessions authorize all actor types, actor IDs, and published RPC methods in exactly one project. Expiry is capped by the requested absolute deadline, 60 seconds, and the runtime maximum JWT lifetime. Session credentials cannot issue sessions or access administrative APIs or WebSockets.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/IssueActorSession" }
responses:
"200":
description: Runtime-signed session and its absolute expiration.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema:
type: object
required: [token, expiresAtMs]
properties:
token: { type: string }
expiresAtMs: { type: integer, format: int64 }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"404": { $ref: "#/components/responses/NotFound" }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/actors/{actor_name}/{actor_id}/find-actor:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
- { $ref: "#/components/parameters/ActorName" }
- { $ref: "#/components/parameters/ActorId" }
post:
operationId: findActor
tags: [Actors]
summary: Find an actor host
security: [{ ApiKey: [] }, { ActorSession: [] }, {}]
description: Resolves placement, starts a host if needed, and issues credentials for direct HTTP calls. Requires an active deployment. Accepts the administrative secret or a runtime-issued actor:session credential for this project. Sessions produce actor-specific tickets containing all of the actor's published RPC methods. These tickets cannot outlive the session.
requestBody: { $ref: "#/components/requestBodies/FindActor" }
responses:
"200": { $ref: "#/components/responses/ActorTarget" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"403": { description: Actor has no published RPC methods. }
"404": { $ref: "#/components/responses/NotFound" }
"409": { $ref: "#/components/responses/Conflict" }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
"500": { $ref: "#/components/responses/Internal" }
"503": { $ref: "#/components/responses/Unavailable" }
/v1/projects/{project_id}/actors/{actor_name}/{actor_id}/invoke:
servers:
- url: "{actorHost}"
description: Use the cached route returned by invokeActor or findActor.
variables:
actorHost: { default: "http://127.0.0.1:7101" }
parameters:
- { $ref: "#/components/parameters/ProjectId" }
- { $ref: "#/components/parameters/ActorName" }
- { $ref: "#/components/parameters/ActorId" }
post:
operationId: invokeActor
tags: [Actors]
summary: Resolve and invoke an actor method
servers:
- url: "{controlPlane}"
description: Resolve and invoke with an API key or project session.
variables:
controlPlane: { default: "http://127.0.0.1:7100" }
- url: "{actorHost}"
description: Cached invocation through the gateway (or local host) with a signed ticket and ownership epoch.
variables:
actorHost: { default: "http://127.0.0.1:7101" }
security: [{ ApiKey: [] }, { ActorSession: [] }, { ActorTicket: [] }, {}]
description: |
Without a valid cached target, the SDK sends requestId, method, args and an optional homeRegion to the control plane.
The control plane resolves placement, forwards one call and returns its outcome together with a scoped host target.
The SDK caches that target for subsequent invocations and broadcasts. Warm invocations use the cached route with its ticket and ownerEpoch. On Kubernetes this is the shared gateway, which verifies the signed route and forwards to the private host.
The host validates the actor, host session and ownership epoch before dispatch.
Socket effects are delivered by the host before a completed response.
The SDK retries once across both paths only for explicit pre-execution rejection or a refused host connection.
When the gateway cannot connect to a cached host, it returns not_executed with reason upstream_not_reached; the SDK clears the target and retries once through control-plane resolution with the same requestId.
A control-plane outcome of unauthenticated means the host rejected its ticket before execution; HTTP 401 means the caller credential was rejected.
Actor failures and ambiguous errors are never automatically replayed. An outcome_unknown error means execution may have occurred.
requestId identifies an attempt; it does not deduplicate execution.
requestBody:
required: true
content:
application/json:
schema:
oneOf:
- { $ref: "#/components/schemas/ActorInvocation" }
- { $ref: "#/components/schemas/ControlPlaneInvocation" }
examples:
resolveAndIncrement:
value: { requestId: request-1, method: increment, args: [2], homeRegion: north-america-west }
increment:
value: { requestId: request-1, ownerEpoch: 3, method: increment, args: [2] }
responses:
"200":
description: Explicit execution outcome, including actor failures. A completed result includes null for void methods.
content:
application/json:
schema:
oneOf:
- { $ref: "#/components/schemas/ControlPlaneInvocationReply" }
- { $ref: "#/components/schemas/ActorInvocationReply" }
examples:
resolved:
value:
target: { homeRegion: north-america-west, route: "https://actors.example.com", token: host-ticket, ownerEpoch: 3, expiresAtMs: 1900000000000 }
outcome: { type: completed, result: 7 }
completed: { value: { type: completed, result: 7 } }
failed: { value: { type: failed, code: actor_error, message: Method failed } }
notExecuted: { value: { type: not_executed, reason: host_unavailable } }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { description: "API key, project session or host ticket rejected before dispatch." }
"403": { description: "Host ticket belongs to another actor, host session or ownership epoch." }
"404": { $ref: "#/components/responses/NotFound" }
"409": { $ref: "#/components/responses/Conflict" }
"502": { description: The invocation outcome is unknown. Do not replay automatically. }
"503": { $ref: "#/components/responses/Unavailable" }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
"415": { description: Expected application/json. }
"422": { description: Invalid invocation document. }
/v1/projects/{project_id}/actors/{actor_name}/{actor_id}/socket-effects:
servers:
- url: "{actorHost}"
description: Use the route returned by findActor.
variables:
actorHost: { default: "http://127.0.0.1:7101" }
parameters:
- { $ref: "#/components/parameters/ProjectId" }
- { $ref: "#/components/parameters/ActorName" }
- { $ref: "#/components/parameters/ActorId" }
post:
operationId: publishActorSocketEffects
tags: [WebSockets]
summary: Deliver socket effects to the owning host
security: [{ ActorTicket: [] }]
description: Used by backend broadcasts. Actor method effects are already delivered by invokeActor. Do not retry an uncertain delivery.
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [ownerEpoch, effects]
properties:
ownerEpoch: { type: integer, minimum: 1, maximum: 9007199254740991 }
effects:
type: array
items: { $ref: "#/components/schemas/ActorSocketEffect" }
examples:
broadcast:
value:
ownerEpoch: 3
effects:
- type: broadcast
message: { type: text, data: '"hello"' }
except_connection_ids: []
tags: []
responses:
"204": { description: Effects delivered. }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { description: Ticket rejected. }
"403": { description: "Ticket belongs to another actor, host session or ownership epoch." }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
"415": { description: Expected application/json. }
"422": { description: Invalid effects document. }
"503": { description: Delivery unavailable; some effects may already have been applied. }
/v1/projects/{project_id}/actors/{actor_name}/{actor_id}/find-websocket:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
- { $ref: "#/components/parameters/ActorName" }
- { $ref: "#/components/parameters/ActorId" }
post:
operationId: findWebSocket
tags: [Actors]
summary: Find an authorized WebSocket URL
description: Issues a fresh connection URL. Authorize the application user before requesting it. Requires an active deployment.
requestBody: { $ref: "#/components/requestBodies/FindWebSocket" }
responses:
"200": { $ref: "#/components/responses/WebSocketGrant" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"409": { $ref: "#/components/responses/Conflict" }
"413": { $ref: "#/components/responses/PayloadTooLarge" }
"500": { $ref: "#/components/responses/Internal" }
"503": { $ref: "#/components/responses/Unavailable" }
/v1/projects/{project_id}/observe/actors:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: getActorInventory
tags: [Observability]
summary: Get actor activity
responses:
"200":
description: Actor counts and connections.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/Inventory" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
"503": { $ref: "#/components/responses/Unavailable" }
/v1/projects/{project_id}/observe/events:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: streamActorInventory
tags: [Observability]
summary: Stream actor activity
description: "SSE: inventory events contain Inventory JSON; error events contain text and close the stream."
responses:
"200": { $ref: "#/components/responses/EventStream" }
"401": { $ref: "#/components/responses/Unauthenticated" }
/v1/projects/{project_id}/observe/state:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: getActorState
tags: [Observability]
summary: Read an actor snapshot from storage
description: Reads existing persisted snapshots without activating the actor. Uploads may lag completed requests. History is limited by the bucket lifecycle.
parameters:
- name: actorName
in: query
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
- name: actorId
in: query
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
- name: version
in: query
schema: { type: integer, minimum: 1 }
responses:
"200":
description: Persisted state inspection result.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/ActorStateResponse" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/state/history:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: listActorStateHistory
tags: [Observability]
summary: List actor snapshot metadata from storage
description: Reads existing persisted snapshots without activating the actor. Uploads may lag completed requests. History is limited by the bucket lifecycle.
parameters:
- name: actorName
in: query
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
- name: actorId
in: query
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
- name: before
in: query
schema: { type: integer, minimum: 1 }
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 100, default: 25 }
responses:
"200":
description: Persisted state inspection result.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/ActorStateHistory" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/requests:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: listRequestHistory
tags: [Observability]
summary: Get request history
description: Newest first. Use nextCursor with the same filters for older records; replace previous records when reset=true.
parameters:
- name: actorName
in: query
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
- name: actorId
in: query
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
- name: requestId
in: query
schema: { type: string, minLength: 1, maxLength: 256 }
- name: connectionId
in: query
schema: { type: string, minLength: 1, maxLength: 256 }
- name: outcome
in: query
schema: { type: string, enum: [completed, failed, rejected, rerouted, interrupted] }
- { $ref: "#/components/parameters/FromMs" }
- { $ref: "#/components/parameters/ToMs" }
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 500, default: 100 }
- name: cursor
in: query
description: nextCursor from the previous page.
schema: { type: string, minLength: 1, maxLength: 4096 }
responses:
"200":
description: Request records; nextCursor is null on the last page.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/TracePage" }
examples:
empty:
value:
{
epoch: "history-1",
cursor: 0,
capacity: 100,
evicted: 0,
dropped: 0,
persistenceFailed: false,
records: [],
nextCursor: null,
resumeCursor: "opaque-cursor",
reset: false
}
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/metrics:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: getObserverMetrics
tags: [Observability]
summary: Get retained request metrics
description: Counts include reroutes; success and p95 use non-rerouted attempts. Returns deployment totals and up to 499 actor classes from retained history.
parameters:
- { $ref: "#/components/parameters/FromMs" }
- { $ref: "#/components/parameters/ToMs" }
responses:
"200":
description: Retained history for the selected range.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/OverviewMetrics" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/queue-waits:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: listQueueWaits
tags: [Observability]
summary: Get queue wait statistics
description: Up to 500 actor instances ordered by admitted request count, then actor name and ID. Includes non-rerouted attempts with a queue wait.
parameters:
- { $ref: "#/components/parameters/FromMs" }
- { $ref: "#/components/parameters/ToMs" }
- name: actorName
in: query
schema: { type: string, minLength: 1, maxLength: 48, pattern: "^[A-Za-z0-9._-]+$" }
responses:
"200":
description: Retained history for the selected range.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema:
type: array
maxItems: 500
items: { $ref: "#/components/schemas/QueueWaitRow" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/websockets:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: listWebSocketSessions
tags: [Observability]
summary: Get WebSocket session history
description: Up to 500 sessions ordered by latest start. Selects sessions whose retained activity span overlaps the inclusive range, keeping their full retained events and connect metadata.
parameters:
- { $ref: "#/components/parameters/FromMs" }
- { $ref: "#/components/parameters/ToMs" }
responses:
"200":
description: Retained history for the selected range.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema:
type: array
maxItems: 500
items: { $ref: "#/components/schemas/SocketSession" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/projects/{project_id}/observe/requests/events:
parameters:
- { $ref: "#/components/parameters/ProjectId" }
get:
operationId: streamRequestHistory
tags: [Observability]
summary: Stream request history
description: |
SSE requests events contain TracePage JSON. Resume with resumeCursor;
when reset=true, replace previous records. Error events contain text and close the stream.
parameters:
- name: after
in: query
description: resumeCursor; overrides Last-Event-ID.
schema: { type: string, maxLength: 4096 }
- name: Last-Event-ID
in: header
description: Previous SSE event ID.
schema: { type: string, maxLength: 4096 }
responses:
"200": { $ref: "#/components/responses/EventStream" }
"400": { $ref: "#/components/responses/InvalidRequest" }
"401": { $ref: "#/components/responses/Unauthenticated" }
"500": { $ref: "#/components/responses/Internal" }
/v1/socket:
get:
operationId: openWebSocket
tags: [WebSockets]
summary: Open a WebSocket
description: Pass websocketUrl from the find-websocket response directly to new WebSocket().
servers:
- url: https://{actorHost}
variables:
actorHost: { default: actor-host.example.com }
security:
- SocketTicket: []
responses:
"101": { description: WebSocket upgrade accepted. }
"400": { $ref: "#/components/responses/UpgradeError" }
"401": { description: Socket authorization rejected. Request a fresh URL. No response body. }
"426":
description: Connection cannot be upgraded to a WebSocket.
content:
text/plain:
schema: { type: string }
"503": { description: Actor host is stopping. No response body. }
webhooks:
socketMessage:
post:
operationId: receiveSocketMessageEvent
tags: [WebSockets]
summary: Receive handled socket messages
description: Set DURABLE_ACTORS_SOCKET_EVENT_URL to enable. When DURABLE_ACTORS_SECRET is configured, callbacks send it as a bearer API key; otherwise the authorization header is omitted. Delivery is best effort, without retries.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/SocketMessageEvent" }
examples:
message:
value:
eventId: 04c842c9-4532-467a-9831-f58f183b110e
actorName: ChatRoom
actorId: lobby
triggerId: null
connectionId: connection-1
message: { type: text, data: '{"type":"post","text":"Hello"}' }
responses:
"2XX": { description: Accepted; no response body required. }
components:
securitySchemes:
ApiKey:
type: http
scheme: bearer
description: Required when DURABLE_ACTORS_SECRET is set on the server. Never send it to browsers.
ActorTicket:
type: http
scheme: bearer
description: Short-lived actor capability returned by findActor. Never use the application API key at the actor host.
ActorSession:
type: http
scheme: bearer
description: Runtime-issued project-scoped session, accepted only for actor RPC discovery.
SocketTicket:
type: apiKey
in: query
name: key
description: Included in websocketUrl. Keep the URL private.
headers:
NoStore:
schema: { type: string, const: no-store }
parameters:
FromMs:
name: fromMs
in: query
description: Inclusive lower bound in Unix milliseconds; must not exceed toMs.
schema: { type: integer, minimum: 0, maximum: 9007199254740991 }
ToMs:
name: toMs
in: query
description: Inclusive upper bound in Unix milliseconds.
schema: { type: integer, minimum: 0, maximum: 9007199254740991 }
ProjectId:
name: project_id
in: path
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,64}$" }
ActorName:
name: actor_name
in: path
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
ActorId:
name: actor_id
in: path
required: true
schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
requestBodies:
FindActor:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/FindActorRequest" }
examples:
default: { value: {} }
regional: { value: { homeRegion: north-america-west } }
FindWebSocket:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/FindWebSocketRequest" }
examples:
socket: { value: { metadata: { userId: alice }, authorizationLifetimeMs: 900000 } }
responses:
Changed:
description: Whether the deployment changed.
content:
application/json:
schema:
type: object
required: [changed]
properties:
changed: { type: boolean }
ActorTarget:
description: Owning host and RPC credentials. Timestamps use Unix milliseconds.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/ActorTarget" }
WebSocketGrant:
description: Authorized WebSocket URL and deadlines. Timestamps use Unix milliseconds.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
application/json:
schema: { $ref: "#/components/schemas/WebSocketGrant" }
EventStream:
description: Server-sent events.
headers:
Cache-Control: { $ref: "#/components/headers/NoStore" }
content:
text/event-stream:
schema: { type: string }
InvalidRequest:
description: Invalid request (invalid_request).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
Unauthenticated:
description: Invalid or missing API key (unauthenticated).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
NotFound:
description: Not found (not_found).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
Conflict:
description: Deployment or region conflict (conflict).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
PayloadTooLarge:
description: Request rejected by an upstream transport limit (payload_too_large).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
Internal:
description: Server failure (internal).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
Unavailable:
description: Temporarily unavailable (unavailable).
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
UpgradeError:
description: Invalid WebSocket upgrade request.
content:
text/plain:
schema: { type: string }
schemas:
OverviewMetrics:
type: object
required: [total, classes]
properties:
total: { $ref: "#/components/schemas/ClassMetrics" }
classes:
type: array
maxItems: 499
items: { $ref: "#/components/schemas/ClassMetrics" }
ClassMetrics:
type: object
required: [actorName, count, success, p95, queueP95]
properties:
actorName: { type: string, description: Empty for the deployment total. }
count: { type: integer, minimum: 0 }
success: { type: [number, "null"], minimum: 0, maximum: 100, description: Completed attempts as a percentage of non-rerouted attempts. }
p95: { type: [number, "null"], minimum: 0, description: 95th percentile duration in milliseconds. }
queueP95: { type: [number, "null"], minimum: 0, description: 95th percentile queue wait in milliseconds. }
QueueWaitRow:
type: object
required: [actorName, actorId, admitted, averageMs, maxMs]
properties:
actorName: { type: string }
actorId: { type: string }
admitted: { type: integer, minimum: 1 }
averageMs: { type: number, minimum: 0 }
maxMs: { type: number, minimum: 0 }
SocketSession:
type: object
required: [connectionId, actorName, actorId, hostId, openedAtMs, closedAtMs, lastSeenMs, messages, failures]
properties:
connectionId: { type: string }
actorName: { type: string }
actorId: { type: string }
hostId: { type: [string, "null"] }
openedAtMs: { type: [integer, "null"], minimum: 0 }
closedAtMs: { type: [integer, "null"], minimum: 0 }
lastSeenMs: { type: [integer, "null"], minimum: 0 }
messages: { type: integer, minimum: 0 }
failures: { type: integer, minimum: 0 }
metadata: { description: Metadata saved with a retained onConnect event. }
ActorBundle:
type: object
additionalProperties: false
required: [bucket, files]
properties:
bucket: { type: string, minLength: 3 }
files:
type: array
minItems: 1
description: Unique relative paths including exactly one actors.mjs or actors.pyz entrypoint. Objects must belong to one immutable artifact deployment.
items:
type: object
additionalProperties: false
required: [path, object, generation, sha256]
properties:
path: { type: string, minLength: 1 }
object: { type: string, minLength: 1 }
generation: { type: integer, minimum: 1 }
sha256: { type: string, pattern: "^[A-Za-z0-9_-]{43}$", description: Base64url-encoded SHA256 without padding. }
LocalSource:
type: object
additionalProperties: false
required: [workingDirectory]
properties:
workingDirectory:
type: string
pattern: "^/"
maxLength: 1024
description: Absolute project directory in the local development server.
actorEntrypoint:
type: [string, "null"]
minLength: 1
maxLength: 1024
default: null
description: TypeScript or Python source path; null uses src/actors.ts.
Deployment:
type: object
additionalProperties: false
oneOf:
- required: [bundle]
- required: [localSource]
properties:
bundle: { $ref: "#/components/schemas/ActorBundle" }
localSource: { $ref: "#/components/schemas/LocalSource" }
secretRefs:
type: array
maxItems: 16
default: []
items: { type: string, pattern: "^[A-Za-z0-9._-]{1,255}$" }
description: Secret names for deployed actors.
contract:
oneOf:
- { $ref: "#/components/schemas/PublicActorContract" }
- { type: "null" }
default: null
description: Optional; generated for hosted deployments.
CurrentDeployment:
type: object
additionalProperties: false
required: [secretRefs]
oneOf:
- required: [bundle]
- required: [localSource]
properties:
bundle: { $ref: "#/components/schemas/ActorBundle" }
localSource: { $ref: "#/components/schemas/LocalSource" }
secretRefs: { $ref: "#/components/schemas/Deployment/properties/secretRefs" }
PublicActorContract:
type: object
additionalProperties: false
required: [version, actors]
properties:
typescript:
type: object
additionalProperties: false
required: [declarations, dependencies]
properties:
declarations: { type: string, minLength: 1 }
dependencies:
type: object
additionalProperties: { type: string, minLength: 1 }
version: { type: integer, const: 1 }
actors:
type: array
items:
type: object
additionalProperties: false
required: [actorName, socket, rpc]
properties:
actorName: { type: string }
description: { type: string, description: Actor documentation for generated clients. }
sandbox: { $ref: "#/components/schemas/SandboxOptions" }
socket:
type: object
additionalProperties: false
required: [version, actorName, schema, emittable]
properties:
version: { type: integer, const: 1 }
actorName: { type: string }
schema: { type: object, description: JSON Schema for socket types. }
emittable: { type: array, uniqueItems: true, items: { type: string } }
rpc:
type: object
additionalProperties: false
required: [schema, methods]
properties:
schema: { type: object, description: JSON Schema for RPC types. }
methods: { type: array, items: { $ref: "#/components/schemas/RpcMethod" } }
SandboxOptions:
type: object
additionalProperties: false
description: Optional actor sandbox overrides compiled from the class decorator. Omitted fields inherit deployment defaults.
properties:
cpu: { type: number, minimum: 0.1, maximum: 64, multipleOf: 0.001 }
memoryMiB: { type: integer, minimum: 128, maximum: 262144 }
idleTimeoutMs: { type: integer, minimum: 1, maximum: 86400000 }
regions:
type: array
minItems: 1
maxItems: 7
uniqueItems: true
description: Allowed compute regions. Order is not a preference; existing actors retain their saved home.
items:
type: string
enum: [canada, north-america-east, north-america-central, north-america-south, north-america-west, europe-west, asia-southeast]
RpcMethod:
type: object
additionalProperties: false
required: [name, parameters, result]
properties:
name: { type: string }
description: { type: string, description: Method documentation for generated clients. }
parameters:
type: array
items:
type: object
additionalProperties: false
required: [name, type, optional, rest]
properties:
name: { type: string }
type: { $ref: "#/components/schemas/RpcType" }
optional: { type: boolean }
rest: { type: boolean }
result:
oneOf:
- type: object
additionalProperties: false
required: [kind]
properties:
kind: { type: string, const: void }
- type: object
additionalProperties: false
required: [kind, type]
properties:
kind: { type: string, const: value }
type: { $ref: "#/components/schemas/RpcType" }
RpcType:
type: object
additionalProperties: false
required: ["$ref"]
properties:
$ref: { type: string, description: Reference into rpc.schema. }
ActorInvocation:
type: object
additionalProperties: false
required: [requestId, ownerEpoch, method, args]
properties:
requestId: { type: string, minLength: 1, maxLength: 255 }
ownerEpoch: { type: integer, minimum: 1, maximum: 9007199254740991 }
method: { type: string, minLength: 1, maxLength: 128 }
args: { type: array, items: {} }
ControlPlaneInvocation:
type: object
additionalProperties: false
required: [requestId, method, args]
properties:
requestId: { type: string, minLength: 1, maxLength: 255 }
method: { type: string, minLength: 1, maxLength: 128 }
args: { type: array, items: {} }
homeRegion: { type: [string, "null"], minLength: 1, maxLength: 64, pattern: "^[a-z0-9-]+$" }
ControlPlaneInvocationReply:
type: object
required: [target, outcome]
properties:
target: { $ref: "#/components/schemas/ActorTarget" }
outcome:
oneOf:
- { $ref: "#/components/schemas/ActorInvocationReply" }
- type: object
required: [type]
properties:
type: { const: unauthenticated }
ActorInvocationMetadata:
type: object
description: Timing and host-start context finalized once by the host request tracker and shared with the response, observability and diagnostic log. Omitted for requests denied before host dispatch.
required: [durationMs, queueWaitMs, hostState, routingMs]
properties:
routingMs:
type: number
minimum: 0
description: Gateway time before the final host dispatch, including host discovery, provisioning and routing retries. Separate from durationMs.
durationMs:
type: number
minimum: 0
description: Total traced host duration in milliseconds, including queue wait, state loading, actor execution and persistence. Ends before the result handoff to the HTTP handler; excludes network transit and subsequent HTTP-handler socket delivery.
queueWaitMs:
type: [number, "null"]
minimum: 0
description: Milliseconds from host submission until the actor worker begins processing, before state loading. Null when processing never begins; otherwise no greater than durationMs.
hostState:
type: string
enum: [cold, warm]
description: Cold when this invocation required actor-host provisioning or activation during routing; warm when routed to an existing host. This is independent of the host's actor-state cache. Host duration excludes provisioning time.
ActorInvocationReply:
oneOf:
- type: object
required: [type, result]
properties:
metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
type: { const: completed }
result: {}
- type: object
required: [type, code, message]
properties:
metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
type: { const: failed }
code: { type: string, minLength: 1, description: "Includes actor_error, unavailable and outcome_unknown." }
message: { type: string }
- type: object
required: [type, reason]
properties:
metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
type: { const: not_executed }
reason:
type: string
enum: [stale_owner, host_unavailable, upstream_not_reached]
ActorSocketEffect:
type: object
description: Host-validated socket effect. Broadcasts require message, except_connection_ids and tags; connection-specific effects require connection_id.
required: [type]
properties:
type: { enum: [state_snapshot, state_update, send, broadcast, close, reject, set_metadata, set_tags] }
connection_id: { type: string }
message:
type: object
required: [type, data]
properties:
type: { enum: [text, binary] }
data: { type: string, description: UTF-8 text or base64-encoded binary. }
except_connection_ids: { type: array, items: { type: string }, maxItems: 128 }
tags: { type: array, items: { type: string }, maxItems: 128 }
tag_match: { enum: [all, any] }
metadata: {}
state: { type: object }
changes: { type: object }
removed: { type: array, items: { type: string } }
version: { type: integer, minimum: 0 }
code: { type: integer, description: "1000 or 3000–4999." }
reason: { type: string }
IssueActorSession:
type: object
additionalProperties: false
required: [subject, expiresAtMs]
properties:
subject: { type: string, minLength: 1, maxLength: 128, description: "Stable opaque credential fingerprint, not a secret." }
expiresAtMs:
{
type: integer,
format: int64,
description: "Absolute authorization deadline in Unix milliseconds. Set this from the start of application authentication, not after it completes."
}
FindActorRequest:
type: object
additionalProperties: false
properties:
homeRegion: { $ref: "#/components/schemas/HomeRegion" }
FindWebSocketRequest:
type: object
additionalProperties: false
required: [metadata]
properties:
homeRegion: { $ref: "#/components/schemas/HomeRegion" }
metadata: { description: Required connection metadata; may be null. Maximum 64 KiB of JSON. }
authorizationLifetimeMs: { type: integer, minimum: 1000, maximum: 86400000, default: 900000 }
HomeRegion:
type: [string, "null"]
pattern: "^[a-z0-9._-]{1,64}$"
description: Region for new actors; cannot change an existing actor's region. Omit or use null for automatic placement.
ActorTarget:
type: object
required: [homeRegion, route, token, ownerEpoch, expiresAtMs]
properties:
homeRegion: { type: string }
route: { type: string, format: uri, description: HTTP(S) origin of the actor HTTP host. }
token: { type: string, description: Bearer token for actor RPCs. }
ownerEpoch: { type: integer, minimum: 0 }
expiresAtMs:
type: integer
format: int64
description: Route cache deadline in Unix milliseconds, bounded by the host idle timeout, host lease, and credential expiry. May precede the token's expiry.
WebSocketGrant:
type: object
required: [homeRegion, websocketUrl, connectByMs, authorizedUntilMs]
properties:
homeRegion: { type: string }
websocketUrl: { type: string, format: uri }
connectByMs: { type: integer, format: int64, description: Connect before this time. }
authorizedUntilMs: { type: integer, format: int64, description: Connection expires at this time. }
Inventory:
type: object
required: [actors, connectionsComplete]
properties:
connectionsComplete:
type: boolean
description: False when a gateway could not be queried; connection lists and counts may be incomplete.
actors:
type: array
items:
type: object
required: [actorName, live, dormant, unknown, instances]
properties:
actorName: { type: string }
live: { type: integer, minimum: 0 }
dormant: { type: integer, minimum: 0 }
unknown: { type: integer, minimum: 0 }
instances:
type: array
items:
type: object
required: [actorId, status, connections, waiting]
properties:
actorId: { type: string }
status: { type: string, enum: [live, dormant, unknown] }
connections:
type: array
items:
type: object
required: [id, metadata]
properties:
id: { type: string }
metadata: {}
waiting:
type: [array, "null"]
items:
type: object
required: [id, operation]
properties:
id: { type: string }
operation: { type: string }
TracePage:
type: object
required: [epoch, cursor, capacity, evicted, dropped, persistenceFailed, records, nextCursor, resumeCursor, reset]
properties:
epoch: { type: string }
cursor: { type: integer, minimum: 0 }
capacity: { type: integer, minimum: 0 }
evicted: { type: integer, minimum: 0 }
dropped: { type: integer, minimum: 0 }
persistenceFailed: { type: boolean }
records: { type: array, items: { $ref: "#/components/schemas/TraceRecord" } }
nextCursor: { type: [string, "null"] }
resumeCursor: { type: string }
reset: { type: boolean }
StateAttribution:
type: [object, "null"]
required: [operation, connectionId, committedAtMs, interleaved]
properties:
operation: { type: string }
connectionId: { type: [string, "null"] }
committedAtMs: { type: integer, minimum: 0 }
interleaved: { type: boolean, description: Other requests may have contributed to this snapshot during reentrant execution. }
StateRecord:
type: object
required: [stateVersion, ownerEpoch, requestId, attribution]
properties:
stateVersion: { type: integer, minimum: 1 }
ownerEpoch: { type: integer, minimum: 1 }
requestId: { type: string }
attribution: { $ref: "#/components/schemas/StateAttribution" }
ActorStateResponse:
type: object
required: [snapshot, schema]
properties:
snapshot:
anyOf:
- type: "null"
- allOf:
- { $ref: "#/components/schemas/StateRecord" }
- type: object
required: [state]
properties:
state: { type: object, additionalProperties: true }
schema: { type: [object, "null"], description: Persisted field schema from the current deployment contract. }
ActorStateHistory:
type: object
required: [records, nextBefore]
properties:
records: { type: array, items: { $ref: "#/components/schemas/StateRecord" } }
nextBefore: { type: [integer, "null"], minimum: 1 }
TraceRecord:
type: object
required: [projectId, sequence, eventId, hostId, sessionId, requestId, actorName, actorId, kind, operation, connectionId, startedAtMs, routingMs, durationMs, queueWaitMs, hostState, outcome]
properties:
projectId: { type: string, pattern: "^[A-Za-z0-9._-]{1,64}$" }
metadata: { description: Bounded JSON metadata from an onConnect event, when retained. }
sequence: { type: integer, minimum: 0 }
eventId: { type: string, format: uuid }
hostId: { type: string }
sessionId: { type: string }
stateVersion: { type: integer, minimum: 1, description: Latest committed version observed when this request completed; signals a storage refresh without duplicating state. }
requestId: { type: string }
actorName: { type: string }
actorId: { type: string }
kind: { type: string, enum: [method, websocket] }
operation: { type: string }
connectionId: { type: [string, "null"] }
startedAtMs: { type: integer, minimum: 0 }
routingMs: { type: number, minimum: 0, description: "Gateway routing and startup time before host dispatch." }
durationMs: { type: number, minimum: 0 }
queueWaitMs: { type: [number, "null"], minimum: 0 }
hostState: { type: string, enum: [cold, warm], description: "Whether routing required host startup. Defaults to warm for historical traces without this field." }
outcome: { type: string, enum: [completed, failed, rejected, rerouted, interrupted] }
SocketMessageEvent:
type: object
required: [eventId, actorName, actorId, triggerId, connectionId, message]
properties:
eventId: { type: string, format: uuid }
actorName: { type: string }
actorId: { type: string }
triggerId: { type: [string, "null"] }
connectionId: { type: string }
message:
oneOf:
- type: object
required: [type, data]
properties:
type: { type: string, const: text }
data: { type: string, description: JSON-encoded message. }
- type: object
required: [type, data]
properties:
type: { type: string, const: binary }
data: { type: string, contentEncoding: base64 }
description: Unsupported by TypeScript actors.
Error:
type: object
required: [error]
properties:
error:
type: object
required: [code, message]
properties:
code: { type: string }
message: { type: string }