API reference
Owner API (P0 display Sessions; P1 interactive Sessions). Request bodies are limited to 256 KiB; a Surface measure (UTF-8 bytes of the canonical Surface JSON) above 131072 bytes is rejected with 413 PAYLOAD_TOO_LARGE. Every table row must have the same key set. Every JSON response carries Cache-Control: no-store, no-transform. Interactive Sessions: active → responded (one accepted response per revision, response_policy first) → active (the owner publishes the next revision) … → completed (terminal).
On this page
- Base URL
https://api.sess.si- Contract
- Sess owner API, version
0.1.0, OpenAPI3.1.0 - Contract SHA-256
8d4c04593b1137cc9730e3836b77173c463e03c7fe1b6cc53a0d51de5890cc65
This page is generated at build time from the same OpenAPI document that the API build checks for drift (packages/spec/openapi.json). It lists only implemented operations.
The running API serves this same document at https://api.sess.si/openapi.json.
Operations
- POST
/v1/auth/email-link - GET
/app/confirm/{token} - POST
/app/confirm/{token} - GET
/app/keys - POST
/app/keys - POST
/app/trials/claim - POST
/v1/trial/sessions - GET
/v1/trial/sessions/{id} - POST
/v1/sessions - GET
/v1/sessions/{id} - PATCH
/v1/sessions/{id} - POST
/v1/sessions/{id}/complete - GET
/v1/sessions/{id}/events - GET
/v1/sessions/{id}/surfaces/{revision} - POST
/s/{token} - GET
/v1/webhook - PUT
/v1/webhook - POST
/v1/webhook/verify - POST
/v1/webhook/secrets/rotate - GET
/v1/sessions/{id}/deliveries - POST
/v1/sessions/{id}/events/{event_id}/redeliver - GET
/.well-known/sess-receipt-keys.json - GET
/openapi.json - GET
/health/live - GET
/health/ready - GET
/version
POST /v1/auth/email-link
Operation ID requestSignInLink
Developer account sign-in. Emails a sign-in link to the address: it works once, expires 15 minutes after issue, and a newer link cancels it once the email provider has confirmed sending the newer one (an unconfirmed send cancels nothing). Signing in with one link cancels the address’s other links. The answer is the same whether or not an account exists. Opening the link shows a page whose Sign in button finishes the sign-in (GET never consumes it). Limits: 5 links per address and 20 per client per rolling hour. Developer sign-in never verifies a human responder.
Authentication: None (public)
Request body (required)
Content type application/json: EmailLinkRequest
no additional properties
-
emailstring requiredThe address to send a sign-in link to. Trimmed and lower-cased.
min length 3 · max length 254
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
202 | Handed to the email provider. | EmailLinkAccepted | — |
400 | INVALID_SCHEMA: not a plausible email address | Error | — |
429 | RATE_LIMITED: too many links for this address or client | Error | Retry-After |
503 | SIGN_IN_UNAVAILABLE (email is not configured on this deployment) or SERVICE_UNAVAILABLE (the email provider did not confirm the send: the outcome is unknown, so an email may or may not arrive; earlier links stay valid, and the attempt counts toward the limits) | Error | — |
{
"email": "[email protected]"
}
GET /app/confirm/{token}
Operation ID signInConfirmPage
The page the emailed link opens (the token is a single-use secret; never log it). It only shows a Sign in button (with ?continue=key, a link requested to finish a key creation: "Continue creating your key"); it consumes nothing.
Authentication: None (public)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
token | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The confirm page. | — | — |
POST /app/confirm/{token}
Operation ID signInConfirm
Consumes the link once (same-origin requests only) and sets the account-page cookie: HttpOnly, Secure, SameSite=Strict, host-only, Path=/app, 12 hours. When the same browser holds a pending key creation of the same account (the key-intent cookie, set by a create post with an expired session of that account), the key is created now with that label and expiry, once, and the response is the one-time reveal; the intent cookie is cleared. A pending creation of another account creates nothing.
Authentication: None (public)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
token | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | Signed in; the pending key was not created because the expiry date its form showed is no longer the date a key created now would get (a new UTC day began): the keys page with a fresh form. | — | — |
201 | Signed in and the pending key created: the keys page with it, shown once. | — | — |
303 | Signed in: to /app/keys (/app/keys?resume=elsewhere when the link was for a key creation started in another browser), with Set-Cookie. | — | — |
400 | SIGN_IN_LINK_INVALID: expired, used or replaced by a newer link. | — | — |
403 | ACTION_NOT_ALLOWED: not a same-origin request. | — | — |
409 | Signed in; the pending key was not created: KEY_LIMIT_REACHED (the account has 10 active keys). | — | — |
GET /app/keys
Operation ID apiKeysPage
The account page listing the workspace’s API keys (label, fingerprint, created, last used, expiry, state). Without a live account session: 303 to /app/sign-in.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The keys page. | — | — |
303 | To /app/sign-in. | — | — |
POST /app/keys
Operation ID createApiKey
Creates an owner API key (sess_sk_…) of the developer workspace and shows it once, in one post of the keys page’s create form. The form states each expiry choice’s exact date and carries a single-use nonce bound to the account session (15 minutes); creating consumes it, so a refresh or repeat never creates a second key or shows the secret again. The stored expiry has the date the form showed (rendered_at, bound to the nonce); when that date is no longer true the form is shown again (400). Form fields: csrf (the page’s token), nonce, rendered_at, label (optional, ≤ 64 characters, no control characters), expires_in_days (30, 90, 365 or never; required). Same-origin requests with the session’s CSRF token only. At most 10 active keys per account. With an expired account session (same-origin posts only), a valid label and expiry choice, bound to that account, is kept in a key-intent cookie (HMAC-protected, HttpOnly, Secure, SameSite=Strict, host-only, Path=/app, 15 minutes) and the answer is 303 to /app/sign-in ("Verify it’s you"); the key is created only after the email link is confirmed in the same browser. Revoke: POST /app/keys/{id}/revoke (same rules), immediate. Sign out: POST /app/sign-out.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
201 | The keys page with the new key, shown once. | — | — |
303 | No live account session: to /app/sign-in (with the key-intent cookie for a valid choice). | — | — |
400 | INVALID_SCHEMA: an expiry that is not offered, an invalid label (the field shows the error), a form nonce that is missing, unknown, expired or issued to another account session, a changed rendered_at, or expiry dates that changed since the form was shown. | — | — |
403 | ACTION_NOT_ALLOWED: cross-origin or a wrong CSRF token. | — | — |
409 | KEY_LIMIT_REACHED, or KEY_ALREADY_CREATED (the same create form again: no second key, and the secret is not shown again). | — | — |
POST /app/trials/claim
Operation ID claimTrial
Claims a no-signup trial for the signed-in developer account. Form fields: csrf (the page’s token) and management_credential (the trial’s sess_mg_… credential, in the form body only, never in a URL). Same-origin requests with the session’s CSRF token only; the human link can never claim. A claim records the account as the trial’s owner, once: nothing moves, the trial keeps its deadlines, limits and deletion time, its receipts stay as issued and its management credential keeps working. The account’s API keys can then read (only read) the trial’s Sessions with the owner read routes, each Session until its result_available_until (as with the management credential). Claiming the same trial again from the same account answers as the first claim.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
303 | Claimed (or already claimed by this account): to /app/keys?claimed=1. No live account session: to /app/sign-in. | — | — |
400 | INVALID_SCHEMA: not a management credential. | — | — |
403 | ACTION_NOT_ALLOWED: cross-origin or a wrong CSRF token. | — | — |
404 | TRIAL_NOT_FOUND: no live trial for that credential (unknown, revoked, deleted or past its deletion time). | — | — |
409 | TRIAL_ALREADY_CLAIMED: another account claimed this trial. | — | — |
POST /v1/trial/sessions
Operation ID createTrialSession
The no-signup trial. Without Authorization: creates a trial workspace and its first interactive Session, and returns the management credential once, in the body. With Authorization: Bearer <management credential>: creates a further Session in that trial. Interactive Sessions only (mode interactive); no return channel, webhook or outbound endpoint exists for a trial. Trial limits (published, reversible): human link and action window 1 hour; result readable 24 hours after the action window; at most 3 active Sessions and 10 Sessions per trial within its 24-hour creation window; at most 3 new trials per client and 200 overall per rolling 24 hours. Any other credential, or a management credential that is unknown, expired, revoked or bound to one Session → 404 NOT_FOUND. An Idempotency-Key header is refused (400 INVALID_SCHEMA): the credential and the human link cannot be replayed.
Authentication: None, or Authorization: Bearer <credential> (managementCredential — The trial management credential (sess_mg_…), returned once at trial creation.)
Request body (required)
Content type application/json: TrialCreateSessionRequest
no additional properties
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object requiredmin items 1 · max items 100
-
typestring requiredmin length 1 · max length 64
-
-
-
actionsarray of object requiredmin items 1 · max items 5
no additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"optionalOne accepted response per revision (the only P1 policy; the default).
-
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
201 | Session created at revision 1. | TrialCreateSessionResponse | ETag, Location |
400 | INVALID_SCHEMA or UNKNOWN_COMPONENT | Error | — |
404 | NOT_FOUND: the credential does not authorize a trial, an unknown /v1/trial path or a malformed trial URL (never 401) | Error | — |
413 | PAYLOAD_TOO_LARGE | Error | — |
429 | RATE_LIMITED: a trial limit (active Sessions, Sessions per trial, new trials per client or overall); also after the trial creation window has ended. The message names the limit in plain words for people; the code and Retry-After are the stable contract, so clients never parse the message. | Error | Retry-After |
500 | INTERNAL | Error | — |
503 | TRIAL_UNAVAILABLE: the trial is not configured on this deployment | Error | — |
{
"interaction": {
"mode": "interactive",
"title": "Review three synthetic invoices",
"description": "Synthetic data. Correct the amount if needed and select the invoices to approve.",
"source": {
"kind": "sess_surface",
"components": [
{
"type": "record",
"label": "INV-1",
"fields": {
"id": "INV-1",
"vendor": "Acme",
"amount": 120
}
},
{
"type": "record",
"label": "INV-2",
"fields": {
"id": "INV-2",
"vendor": "Globex",
"amount": 75.5
}
},
{
"type": "record",
"label": "INV-3",
"fields": {
"id": "INV-3",
"vendor": "Initech",
"amount": 990
}
},
{
"type": "field",
"name": "inv_3_amount",
"label": "INV-3 amount",
"required": true,
"schema": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"value": 990
},
{
"type": "field",
"name": "approved",
"label": "Invoices to approve",
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3
},
"value": []
}
]
},
"actions": [
{
"id": "submit",
"label": "Submit review",
"intent": "submit"
}
]
}
}
{
"id": "ses_01JABCDEFGHJKMNPQRSTVWXYZ0",
"revision": 1,
"human_url": "https://sess.example/s/{token}",
"workspace_id": "wks_0123456789abcdef0123",
"management_credential": "sess_mg_SYNTHETICxEXAMPLExNOTxAxCREDENTIALxxxxxxxxx",
"action_expires_at": "2026-01-01T01:00:00.000Z",
"result_available_until": "2026-01-02T01:00:00.000Z",
"trial_expires_at": "2026-01-02T00:00:00.000Z"
}
GET /v1/trial/sessions/{id}
Operation ID getTrialSession
A trial Session and its accepted responses, read with the trial’s management credential, until result_available_until. Reading never consumes or changes it. A Session of another trial or workspace, an unknown, expired or revoked credential, a human link or an owner key → 404 NOT_FOUND (generic).
Authentication: Authorization: Bearer <credential> (managementCredential — The trial management credential (sess_mg_…), returned once at trial creation.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The Session with its trial timing. | TrialSessionResponse | ETag |
404 | NOT_FOUND: any credential or isolation failure, an unknown /v1/trial path or a malformed trial URL (never 401 or 400) | Error | — |
500 | INTERNAL | Error | — |
503 | TRIAL_UNAVAILABLE: the trial is not configured on this deployment | Error | — |
{
"id": "ses_01JABCDEFGHJKMNPQRSTVWXYZ0",
"status": "responded",
"revision": 1,
"interaction": {
"mode": "interactive",
"title": "Review three synthetic invoices",
"description": "Synthetic data. Correct the amount if needed and select the invoices to approve.",
"source": {
"kind": "sess_surface",
"components": [
{
"type": "record",
"label": "INV-1",
"fields": {
"id": "INV-1",
"vendor": "Acme",
"amount": 120
}
},
{
"type": "record",
"label": "INV-2",
"fields": {
"id": "INV-2",
"vendor": "Globex",
"amount": 75.5
}
},
{
"type": "record",
"label": "INV-3",
"fields": {
"id": "INV-3",
"vendor": "Initech",
"amount": 990
}
},
{
"type": "field",
"name": "inv_3_amount",
"label": "INV-3 amount",
"required": true,
"schema": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"value": 990
},
{
"type": "field",
"name": "approved",
"label": "Invoices to approve",
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3
},
"value": []
}
]
},
"actions": [
{
"id": "submit",
"label": "Submit review",
"intent": "submit"
}
],
"response_policy": "first"
},
"response_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"inv_3_amount": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"approved": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3,
"uniqueItems": true
}
},
"required": [
"inv_3_amount"
],
"additionalProperties": false
},
"responses": [
{
"event_id": "evt_01JABCDEFGHJKMNPQRSTVWXYZ1",
"sequence": 1,
"revision": 1,
"action_id": "submit",
"data": {
"inv_3_amount": 909,
"approved": [
"INV-1",
"INV-3"
]
},
"actor": {
"assurance": "link_holder"
},
"accepted_at": "2026-01-01T00:00:00.000Z",
"receipt": "synthetic-protected-header.synthetic-claims.synthetic-signature"
}
],
"trial": {
"workspace_id": "wks_0123456789abcdef0123",
"action_expires_at": "2026-01-01T01:00:00.000Z",
"result_available_until": "2026-01-02T01:00:00.000Z"
}
}
POST /v1/sessions
Operation ID createSession
Creates a display Session (mode display, source.kind data) or an interactive one (mode interactive, source.kind sess_surface; components: SurfaceComponent). An unrecognized component type → 400 UNKNOWN_COMPONENT; a field-schema keyword outside the supported subset → 400 INVALID_SCHEMA. An Idempotency-Key header is refused (400 INVALID_SCHEMA): the human link cannot be replayed (it is stored only as a hash). Retention: the human link expires 720 hours after creation with the deployment owner key and 168 hours with a developer API key (free plan). The Session’s content, accepted results and receipts are purged 720 hours (owner key) or 168 hours (developer API key) after the earlier of its completion and its link’s expiry, and outstanding webhook deliveries are cancelled; afterwards every owner route answers 404 SESSION_NOT_FOUND. A webhook already delivered is not recalled.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Request body (required)
Content type application/json: CreateSessionRequest
no additional properties
-
interactionobject or object required
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
201 | Session created at revision 1. | CreateSessionResponse | ETag, Location |
400 | INVALID_SCHEMA or UNKNOWN_COMPONENT | Error | — |
401 | UNAUTHORIZED | Error | — |
413 | PAYLOAD_TOO_LARGE | Error | — |
500 | INTERNAL | Error | — |
{
"interaction": {
"mode": "display",
"title": "Synthetic example",
"description": "Synthetic data.",
"source": {
"kind": "data",
"data": {
"reference": "REF-1",
"profile": {
"name": "Example",
"active": true
},
"rows": [
{
"id": "r1",
"amount": 1
},
{
"id": "r2",
"amount": 2
}
]
}
}
}
}
{
"interaction": {
"mode": "interactive",
"title": "Review three synthetic invoices",
"description": "Synthetic data. Correct the amount if needed and select the invoices to approve.",
"source": {
"kind": "sess_surface",
"components": [
{
"type": "record",
"label": "INV-1",
"fields": {
"id": "INV-1",
"vendor": "Acme",
"amount": 120
}
},
{
"type": "record",
"label": "INV-2",
"fields": {
"id": "INV-2",
"vendor": "Globex",
"amount": 75.5
}
},
{
"type": "record",
"label": "INV-3",
"fields": {
"id": "INV-3",
"vendor": "Initech",
"amount": 990
}
},
{
"type": "field",
"name": "inv_3_amount",
"label": "INV-3 amount",
"required": true,
"schema": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"value": 990
},
{
"type": "field",
"name": "approved",
"label": "Invoices to approve",
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3
},
"value": []
}
]
},
"actions": [
{
"id": "submit",
"label": "Submit review",
"intent": "submit"
}
]
}
}
GET /v1/sessions/{id}
Operation ID getSession
The Session. Interactive Sessions return status, the current revision, its response_schema and every accepted response bound to its revision; repeated reads of an unchanged Session are byte-identical. A developer API key also reads the Sessions of trials its account claimed (read-only), each until that Session’s result_available_until.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The current revision of the Session. | SessionResponse or InteractiveSessionResponse | ETag |
400 | INVALID_SCHEMA | Error | — |
401 | UNAUTHORIZED | Error | — |
404 | SESSION_NOT_FOUND | Error | — |
500 | INTERNAL | Error | — |
{
"id": "ses_01JABCDEFGHJKMNPQRSTVWXYZ0",
"status": "responded",
"revision": 1,
"interaction": {
"mode": "interactive",
"title": "Review three synthetic invoices",
"description": "Synthetic data. Correct the amount if needed and select the invoices to approve.",
"source": {
"kind": "sess_surface",
"components": [
{
"type": "record",
"label": "INV-1",
"fields": {
"id": "INV-1",
"vendor": "Acme",
"amount": 120
}
},
{
"type": "record",
"label": "INV-2",
"fields": {
"id": "INV-2",
"vendor": "Globex",
"amount": 75.5
}
},
{
"type": "record",
"label": "INV-3",
"fields": {
"id": "INV-3",
"vendor": "Initech",
"amount": 990
}
},
{
"type": "field",
"name": "inv_3_amount",
"label": "INV-3 amount",
"required": true,
"schema": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"value": 990
},
{
"type": "field",
"name": "approved",
"label": "Invoices to approve",
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3
},
"value": []
}
]
},
"actions": [
{
"id": "submit",
"label": "Submit review",
"intent": "submit"
}
],
"response_policy": "first"
},
"response_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"inv_3_amount": {
"type": "number",
"minimum": 0,
"maximum": 100000
},
"approved": {
"type": "array",
"items": {
"type": "string",
"enum": [
"INV-1",
"INV-2",
"INV-3"
]
},
"maxItems": 3,
"uniqueItems": true
}
},
"required": [
"inv_3_amount"
],
"additionalProperties": false
},
"responses": [
{
"event_id": "evt_01JABCDEFGHJKMNPQRSTVWXYZ1",
"sequence": 1,
"revision": 1,
"action_id": "submit",
"data": {
"inv_3_amount": 909,
"approved": [
"INV-1",
"INV-3"
]
},
"actor": {
"assurance": "link_holder"
},
"accepted_at": "2026-01-01T00:00:00.000Z",
"receipt": "synthetic-protected-header.synthetic-claims.synthetic-signature"
}
]
}
PATCH /v1/sessions/{id}
Operation ID publishRevision
Publishes the next immutable Surface revision of an interactive Session, from responded or active (superseding the unanswered revision). The Session returns to active on the same Session ID and human link; a submission against an older revision is then refused with SESSION_REVISION_CONFLICT.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
If-Match | header | string | yes | The strong ETag from the latest GET (e.g. "2.3"). Required: absent or * → 428 PRECONDITION_REQUIRED. A weak tag (W/"…") never matches (strong comparison); a stale tag → 412 SESSION_REVISION_CONFLICT. |
Idempotency-Key | header | string | no | Scoped to the owner credential, the operation and the Session. The same canonical request (body and If-Match) returns the original result (status, ETag, body); a different request with the same key → 409 IDEMPOTENCY_CONFLICT. Only successful results are recorded. |
Request body (required)
Content type application/json: PatchSessionRequest
no additional properties
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object requiredmin items 1 · max items 100
-
typestring requiredmin length 1 · max length 64
-
-
-
actionsarray of object requiredmin items 1 · max items 5
no additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"optionalOne accepted response per revision (the only P1 policy; the default).
-
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The Session at its new revision. | InteractiveSessionResponse | ETag |
400 | INVALID_SCHEMA or UNKNOWN_COMPONENT | Error | — |
401 | UNAUTHORIZED | Error | — |
403 | ACTION_NOT_ALLOWED: a Session of a claimed trial (read-only) | Error | — |
404 | SESSION_NOT_FOUND | Error | — |
409 | SESSION_COMPLETED, ACTION_NOT_ALLOWED (display Session) or IDEMPOTENCY_CONFLICT | Error | — |
412 | SESSION_REVISION_CONFLICT (If-Match does not match the current ETag) | Error | — |
413 | PAYLOAD_TOO_LARGE | Error | — |
428 | PRECONDITION_REQUIRED | Error | — |
500 | INTERNAL | Error | — |
POST /v1/sessions/{id}/complete
Operation ID completeSession
Completes an interactive Session explicitly. Terminal: a completed Session accepts no further submission or revision. No request body.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
If-Match | header | string | yes | The strong ETag from the latest GET (e.g. "2.3"). Required: absent or * → 428 PRECONDITION_REQUIRED. A weak tag (W/"…") never matches (strong comparison); a stale tag → 412 SESSION_REVISION_CONFLICT. |
Idempotency-Key | header | string | no | Scoped to the owner credential, the operation and the Session. The same canonical request (body and If-Match) returns the original result (status, ETag, body); a different request with the same key → 409 IDEMPOTENCY_CONFLICT. Only successful results are recorded. |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The completed Session. | InteractiveSessionResponse | ETag |
400 | INVALID_SCHEMA | Error | — |
401 | UNAUTHORIZED | Error | — |
403 | ACTION_NOT_ALLOWED: a Session of a claimed trial (read-only) | Error | — |
404 | SESSION_NOT_FOUND | Error | — |
409 | SESSION_COMPLETED, ACTION_NOT_ALLOWED (display Session) or IDEMPOTENCY_CONFLICT | Error | — |
412 | SESSION_REVISION_CONFLICT | Error | — |
428 | PRECONDITION_REQUIRED | Error | — |
500 | INTERNAL | Error | — |
GET /v1/sessions/{id}/events
Operation ID listSessionEvents
Every Event of the Session in sequence order: response.accepted (actor link_holder, the revision it was accepted on, action_id and the typed data), revision.published and session.completed (actor owner). Append-only: Event IDs and sequences never change, and every accepted result stays listed after later revisions and completion. Not paginated in P1 (a Session has a few Events per round). Display Sessions have none. Cache-Control: no-store, no-transform.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The Event log. | SessionEventsResponse | — |
401 | UNAUTHORIZED | Error | — |
404 | SESSION_NOT_FOUND | Error | — |
500 | INTERNAL | Error | — |
GET /v1/sessions/{id}/surfaces/{revision}
Operation ID getSurfaceRevision
One immutable Surface revision exactly as stored: the interaction (and, for an interactive Session, the response schema) that responses on that revision are bound to. Cache-Control: no-store, no-transform.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
revision | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The revision. | SessionResponse or InteractiveSurfaceResponse | — |
400 | INVALID_SCHEMA (revision is not a positive integer) | Error | — |
401 | UNAUTHORIZED | Error | — |
404 | SESSION_NOT_FOUND, or NOT_FOUND for a revision that does not exist | Error | — |
500 | INTERNAL | Error | — |
POST /s/{token}
Operation ID submitHumanAction
The human form submission (the human link is the capability; never log it). Accepted only from the page itself: Sec-Fetch-Site same-origin, or without Fetch Metadata an Origin equal to the public origin. The server resolves action_id from the exact stored revision and validates data against its response_schema. Responses are HTML pages whose stable code is in a data-error-code attribute.
Authentication: None (public)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
token | path | string | yes |
Request body (required)
Content type application/x-www-form-urlencoded: HumanSubmissionForm
properties named ^data\.[a-z][a-z0-9_]{0,63}$: string · no additional properties
-
client_event_idstring requiredpattern
^[A-Za-z0-9_-]{16,64}$ -
surface_revisionstring requiredpattern
^[1-9][0-9]{0,8}$ -
action_idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | Accepted (with a signed decision receipt stored with its Event, returned by the owner GET and the Event log), or a repeated client_event_id with the same request (original result and the same receipt, never re-signed). | — | — |
400 | INVALID_SCHEMA or ACTION_NOT_FOUND. | — | — |
403 | ACTION_NOT_ALLOWED: not a same-origin submission. | — | — |
404 | Unknown, expired or revoked link (generic). | — | — |
405 | ACTION_NOT_ALLOWED: a display Session. | — | — |
409 | SESSION_REVISION_CONFLICT (the current revision, prefilled with the safe draft), RESPONSE_LIMIT_REACHED, SESSION_COMPLETED or IDEMPOTENCY_CONFLICT. | — | — |
413 | PAYLOAD_TOO_LARGE. | — | — |
415 | INVALID_SCHEMA: not application/x-www-form-urlencoded. | — | — |
422 | VALIDATION_FAILED: the form with field errors. | — | — |
503 | SERVICE_UNAVAILABLE: the receipt keys are not configured; nothing is accepted. | — | — |
GET /v1/webhook
Operation ID getWebhook
The endpoint, the signing secrets in force (key IDs only) and delivery counts with the age of the oldest pending delivery.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The webhook state. | WebhookResponse | — |
401 | UNAUTHORIZED | Error | — |
PUT /v1/webhook
Operation ID registerWebhook
Registers the owner workspace’s webhook endpoint (one return channel). It replaces the current endpoint, whose pending deliveries are not redirected (they fail as endpoint_unavailable; redeliver explicitly), and receives nothing until verified. The first registration also creates the signing secret, returned once. 503 SERVICE_UNAVAILABLE while data-encryption keys are not configured.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Request body (required)
Content type application/json: WebhookRegisterRequest
no additional properties
-
urlstring requiredAbsolute https:// URL on port 443, without user info or fragment. Registering replaces the current endpoint (which stops receiving new deliveries); the new one receives nothing until verified.
min length 1 · max length 2048
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
201 | Registered (pending). | WebhookRegisterResponse | — |
400 | WEBHOOK_INVALID_URL (reason: not_https, port, credentials, fragment, non_public_address, malformed, too_long) or INVALID_SCHEMA | Error | — |
401 | UNAUTHORIZED | Error | — |
503 | SERVICE_UNAVAILABLE | Error | — |
POST /v1/webhook/verify
Operation ID verifyWebhook
POSTs a fresh random challenge to the exact registered URL through the delivery egress policy; the endpoint is verified when it echoes it, for 30 days (verification_expires_at). Verifying again renews it; an expired verification reads as pending (no new deliveries; queued ones fail endpoint_unavailable). Every connection resolves the host and refuses non-public addresses.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Responses
POST /v1/webhook/secrets/rotate
Operation ID rotateWebhookSecret
Creates a new signing secret (returned once). The previous one keeps signing for a 24-hour overlap, so deliveries carry both signatures until then.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
201 | Rotated. | WebhookRotateResponse | — |
401 | UNAUTHORIZED | Error | — |
409 | WEBHOOK_NOT_CONFIGURED | Error | — |
503 | SERVICE_UNAVAILABLE | Error | — |
GET /v1/sessions/{id}/deliveries
Operation ID listDeliveries
Every webhook delivery job of the Session’s accepted responses with every attempt (outcome and HTTP status), including permanent failures and exhausted retries.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The delivery log. | DeliveriesResponse | — |
401 | UNAUTHORIZED | Error | — |
404 | SESSION_NOT_FOUND | Error | — |
POST /v1/sessions/{id}/events/{event_id}/redeliver
Operation ID redeliverEvent
Queues the accepted Event for delivery again to the current verified endpoint, with a fresh retry budget. The message is the same bytes (same event_id and receipt). A delivery already pending for the Event to the current endpoint is returned instead; one pending for a replaced endpoint is ended (endpoint_unavailable) and a new one queued.
Authentication: Authorization: Bearer <credential> (ownerKey — An owner credential: the deployment owner key (acts in the operator workspace) or a developer API key sess_sk_… from the account pages (acts only in its developer workspace; a revoked or expired key → 401 UNAUTHORIZED). A Session of another workspace is 404 SESSION_NOT_FOUND.)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
event_id | path | string | yes |
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
202 | Queued. | — | — |
401 | UNAUTHORIZED | Error | — |
403 | ACTION_NOT_ALLOWED: a Session of a claimed trial (read-only) | Error | — |
404 | NOT_FOUND (no such accepted Event in this Session) | Error | — |
409 | WEBHOOK_NOT_CONFIGURED (no verified endpoint) | Error | — |
GET /.well-known/sess-receipt-keys.json
Operation ID receiptKeys
The public decision-receipt verification keys as a JWK Set (Ed25519, alg EdDSA): the active signing key and every retained key of the rotation overlap. Verify a receipt (compact JWS, typ sess-receipt+jwt) with the key its protected header kid names, issuer = this origin, audience = the Session’s workspace (wks_operator for owner-API Sessions, the trial’s workspace_id for trial Sessions). No credential. 503 SERVICE_UNAVAILABLE while the receipt keys are not configured. Cache-Control: no-store, no-transform.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The JWK Set. | ReceiptKeysResponse | — |
503 | SERVICE_UNAVAILABLE | Error | — |
GET /openapi.json
Operation ID openApi
This document: the generated, CI-drift-checked contract of the artifact.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The OpenAPI 3.1 document. | — | — |
GET /health/live
Operation ID healthLive
Process liveness only: no dependency is called. Cache-Control: no-store.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The process is running. | HealthOk | — |
GET /health/ready
Operation ID healthReady
Readiness, checked within a bound and never cached: the owner key and the decision-receipt signing keys are configured and usable, the build identity is complete and valid (git_sha, build_id and build_time are all non-null in /version), the database answers, and every migration bundled with the artifact is applied. Concurrent requests share the check in progress; the next request after it settles runs a new one. Never migrates and never calls a telemetry backend. Query parameters are ignored. Cache-Control: no-store.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | Ready to serve. | HealthOk | — |
503 | Not ready: configuration, database or schema. No detail is disclosed. | HealthUnavailable | — |
GET /version
Operation ID version
Non-secret build identity. Answers 200 even when readiness does not. git_sha, build_id and build_time are each null when not supplied or invalid (git_sha: SESS_GIT_SHA missing, empty or malformed; build_time also while it is more than 5 s in the future, checked per request); any null fails readiness (503). Cache-Control: no-store.
Authentication: None (public)
Responses
| Status | Description | Body | Headers |
|---|---|---|---|
200 | The build identity of the running artifact. | VersionResponse | — |
{
"git_sha": "0123456789abcdef0123456789abcdef01234567",
"build_id": "synthetic-build-1",
"build_time": "2026-01-01T00:00:00Z",
"node_version": "v24.21.0"
}
{
"git_sha": null,
"build_id": "synthetic-build-1",
"build_time": "2026-01-01T00:00:00Z",
"node_version": "v24.21.0"
}
Webhooks sent by Sess
Requests Sess sends to your registered, verified endpoint.
POST responseAccepted
Operation ID webhookResponseAccepted
Sent for every accepted response while the workspace has a verified endpoint. Signed per workspace (Standard Webhooks v1): webhook-id = event_id (stable across retries and redeliveries: deduplicate on it), webhook-timestamp (seconds), webhook-signature = space-separated v1,<base64 HMAC-SHA256(secret, id.timestamp.body)>, one per secret in force (two during a 24-hour rotation overlap), sess-webhook-key-ids = their key IDs. HTTPS on port 443, no redirects followed, 10-second timeout, response read up to 64 KiB. 2xx = accepted by the endpoint (not that the workflow resumed); 5xx, 429 (Retry-After honored up to 1 h), 408, 425, timeouts and disconnects are retried with jitter up to 12 attempts within 24 h (a job out of budget ends exhausted); 3xx and other 4xx (including 401/403) are permanent. Delivery is at least once.
Body: application/json: WebhookDelivery
POST endpointVerification
Operation ID webhookEndpointVerification
Sent by POST /v1/webhook/verify to the exact registered URL, signed like deliveries. Answer 2xx with a JSON body (at most 4 KiB) {"challenge": <the same value>}.
Body: application/json: WebhookVerification
Error codes
Errors use one envelope: {"error": {"code", "message", "request_id"}}. Branch on code, never on message. Quote request_id when you contact support.
INVALID_SCHEMAPAYLOAD_TOO_LARGEUNAUTHORIZEDSESSION_NOT_FOUNDNOT_FOUNDINTERNALUNKNOWN_COMPONENTSESSION_REVISION_CONFLICTIDEMPOTENCY_CONFLICTPRECONDITION_REQUIREDSESSION_COMPLETEDACTION_NOT_ALLOWEDACTION_NOT_FOUNDVALIDATION_FAILEDRESPONSE_LIMIT_REACHEDSERVICE_UNAVAILABLERATE_LIMITEDTRIAL_UNAVAILABLESIGN_IN_UNAVAILABLEWEBHOOK_INVALID_URLWEBHOOK_VERIFICATION_FAILEDWEBHOOK_NOT_CONFIGURED
Schemas
CreateSessionRequest
no additional properties
-
interactionobject or object required
CreateSessionResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
revisioninteger requiredminimum 1
-
human_urlstring required
SessionResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
revisioninteger requiredminimum 1
-
interactionobject requiredno additional properties
-
mode"display"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"data"required -
datamap of string to string or number or boolean or null or map of string to string or number or boolean or null or array of map of string to string or number or boolean or null requiredmin properties 1
-
-
InteractiveSessionResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
status"active"or"responded"or"completed"required -
revisioninteger requiredThe current Surface revision.
minimum 1
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object or object or object or object required
-
-
actionsarray of object requiredno additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"required
-
-
response_schemaobject requiredThe JSON Schema 2020-12 the current revision’s responses are validated against.
-
responsesarray of object requiredEvery accepted response, in sequence order, each bound to its revision.
no additional properties
-
event_idstring requiredpattern
^evt_[0-9A-HJKMNP-TV-Z]{26}$ -
sequenceinteger requiredMonotonic per-Session Event sequence.
minimum 1
-
revisioninteger requiredThe Surface revision it was accepted on.
minimum 1
-
action_idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
dataobject requiredThe normalized typed result, valid against that revision’s response_schema.
-
actorobject requiredno additional properties
-
assurance"link_holder"required
-
-
accepted_atstring requiredISO 8601 UTC time of acceptance.
-
receiptstring or null requiredThe signed decision receipt: a compact JWS (EdDSA/Ed25519, typ sess-receipt+jwt, kid) over the RFC 8785 canonical claims, verifiable with GET /.well-known/sess-receipt-keys.json. Issued once in the acceptance transaction and never re-signed. Its exp is at least 720 hours after acceptance and, for an owner-key Session that is purged automatically, no earlier than the Session’s latest possible purge (its human link’s expiry plus its retention after it ends). null only for responses accepted before receipts existed.
-
InteractiveSurfaceResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
revisioninteger requiredminimum 1
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object or object or object or object required
-
-
actionsarray of object requiredno additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"required
-
-
response_schemaobject required
SessionEventsResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
eventsarray of object requiredEvery Event of the Session, in sequence order (append-only; never rewritten).
no additional properties
-
event_idstring requiredpattern
^evt_[0-9A-HJKMNP-TV-Z]{26}$ -
sequenceinteger requiredMonotonic per-Session sequence.
minimum 1
-
type"response.accepted"or"revision.published"or"session.completed"required -
revisioninteger requiredresponse.accepted: the revision the response was accepted on; revision.published: the revision published; session.completed: the current revision at completion.
minimum 1
-
actorobject requiredno additional properties
-
assurance"link_holder"or"owner"required
-
-
action_idstring optionalpattern
^[a-z][a-z0-9_]{0,31}$ -
dataobject optionalresponse.accepted only: the typed result, valid against that revision.
-
created_atstring requiredISO 8601 UTC time the Event was recorded.
-
receiptstring or null optionalThe signed decision receipt: a compact JWS (EdDSA/Ed25519, typ sess-receipt+jwt, kid) over the RFC 8785 canonical claims, verifiable with GET /.well-known/sess-receipt-keys.json. Issued once in the acceptance transaction and never re-signed. Its exp is at least 720 hours after acceptance and, for an owner-key Session that is purged automatically, no earlier than the Session’s latest possible purge (its human link’s expiry plus its retention after it ends). null only for responses accepted before receipts existed.
-
ReceiptKeysResponse
no additional properties
-
keysarray of object requiredThe active signing key and every retained verification key (rotation overlap). A receipt verifies with the key whose kid its protected header names; there is no fallback key.
no additional properties
-
kty"OKP"required -
crv"Ed25519"required -
xstring required -
kidstring requiredpattern
^[A-Za-z0-9._-]{1,64}$ -
alg"EdDSA"required -
use"sig"required
-
WebhookRegisterRequest
no additional properties
-
urlstring requiredAbsolute https:// URL on port 443, without user info or fragment. Registering replaces the current endpoint (which stops receiving new deliveries); the new one receives nothing until verified.
min length 1 · max length 2048
WebhookRegisterResponse
no additional properties
-
endpointobject requiredno additional properties
-
idstring requiredpattern
^whe_[0-9A-HJKMNP-TV-Z]{26}$ -
urlstring required -
status"pending"or"verified"required -
created_atstring required -
verified_atstring or null required -
verification_expires_atstring or null requiredThe verification lapses 30 days after it succeeds; after that the endpoint is pending again (no new deliveries; queued ones fail endpoint_unavailable) until re-verified.
-
-
signing_secretobject or null requiredThe workspace’s first signing secret when this registration created it, else null.
WebhookResponse
no additional properties
-
endpointobject or null required -
signing_secretsarray of object requiredSecrets in force, newest first (never the secret values).
no additional properties
-
kidstring required -
activeboolean required -
retire_atstring or null required
-
-
deliveriesobject requiredno additional properties
-
pendinginteger requiredminimum 0
-
failedinteger requiredminimum 0
-
deliveredinteger requiredminimum 0
-
oldest_pending_age_secondsinteger or null required
-
WebhookRotateResponse
no additional properties
-
signing_secretobject requiredno additional properties
-
kidstring requiredpattern
^wk_[0-9A-HJKMNP-TV-Z]{26}$ -
secretstring requiredShown once. Store it in the receiver; Sess keeps it only encrypted.
pattern
^whsec_[A-Za-z0-9+/]{43}=$
-
-
previousobject or null required
DeliveriesResponse
no additional properties
-
idstring required -
deliveriesarray of object requiredno additional properties
-
delivery_idstring requiredpattern
^obx_[0-9A-HJKMNP-TV-Z]{26}$ -
event_idstring required -
kind"accepted"or"redelivery"required -
status"pending"or"delivered"or"failed"required -
endpoint_idstring required -
next_attempt_atstring or null required -
deadline_atstring required -
created_atstring required -
finished_atstring or null required -
last_outcome"started"or"delivered"or"server_error"or"rate_limited"or"timeout"or"connection"or"dns"or"signing_unavailable"or"request_timeout"or"too_early"or"rejected"or"redirect"or"egress_refused"or"endpoint_unavailable"or"exhausted"or null requiredThe job-level outcome: the last attempt’s, or
exhaustedwhen the attempt or time budget ran out, orendpoint_unavailablewhen its endpoint was replaced, disabled or its verification lapsed. -
attemptsarray of object requiredEvery started attempt.
startedwith no finish time: the attempt was interrupted (e.g. a crash); the outcome at the endpoint is unknown and the job is retried.no additional properties
-
attemptinteger requiredminimum 1
-
started_atstring required -
finished_atstring or null required -
outcome"started"or"delivered"or"server_error"or"rate_limited"or"timeout"or"connection"or"dns"or"signing_unavailable"or"request_timeout"or"too_early"or"rejected"or"redirect"or"egress_refused"or"endpoint_unavailable"or"exhausted"required -
http_statusinteger or null required
-
-
WebhookDelivery
no additional properties
-
type"response.accepted"required -
event_idstring requiredStable across retries and redeliveries: deduplicate on it.
-
session_idstring required -
sequenceinteger required -
revisioninteger required -
action_idstring required -
dataobject required -
accepted_atstring required -
receiptstring or null requiredThe stored signed decision receipt (identical on every delivery).
WebhookVerification
no additional properties
-
type"sess.webhook.verification"required -
challengestring required
PatchSessionRequest
no additional properties
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object requiredmin items 1 · max items 100
-
typestring requiredmin length 1 · max length 64
-
-
-
actionsarray of object requiredmin items 1 · max items 5
no additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"optionalOne accepted response per revision (the only P1 policy; the default).
-
SurfaceComponent
Type: object or object or object or object
HumanSubmissionForm
properties named ^data\.[a-z][a-z0-9_]{0,63}$: string · no additional properties
-
client_event_idstring requiredpattern
^[A-Za-z0-9_-]{16,64}$ -
surface_revisionstring requiredpattern
^[1-9][0-9]{0,8}$ -
action_idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$
Error
no additional properties
-
errorobject requiredno additional properties
-
code"INVALID_SCHEMA"or"PAYLOAD_TOO_LARGE"or"UNAUTHORIZED"or"SESSION_NOT_FOUND"or"NOT_FOUND"or"INTERNAL"or"UNKNOWN_COMPONENT"or"SESSION_REVISION_CONFLICT"or"IDEMPOTENCY_CONFLICT"or"PRECONDITION_REQUIRED"or"SESSION_COMPLETED"or"ACTION_NOT_ALLOWED"or"ACTION_NOT_FOUND"or"VALIDATION_FAILED"or"RESPONSE_LIMIT_REACHED"or"SERVICE_UNAVAILABLE"or"RATE_LIMITED"or"TRIAL_UNAVAILABLE"or"SIGN_IN_UNAVAILABLE"or"WEBHOOK_INVALID_URL"or"WEBHOOK_VERIFICATION_FAILED"or"WEBHOOK_NOT_CONFIGURED"required -
messagestring required -
request_idstring requiredmin length 1
-
reasonstring optionalA stable machine-readable refinement of some codes (P1 A4 webhook errors).
pattern
^[a-z_]{1,40}$
-
HealthOk
no additional properties
-
status"ok"required
VersionResponse
no additional properties
-
git_shastring or null requiredThe deployed commit, from SESS_GIT_SHA. null when SESS_GIT_SHA is missing, empty or not exactly 40 lower-case hex characters; readiness then answers 503. Never derived from a checkout or normalized.
-
build_idstring or null requiredSESS_BUILD_ID, else the BUILD_ID file at the workspace root of the image. null when neither supplies a valid one; readiness then answers 503.
-
build_timestring or null requiredISO 8601 UTC build time, from SESS_BUILD_TIME, else the BUILD_TIME file at the workspace root of the image. Valid when it has real calendar components and is not more than 5 s after the current time, checked on every request. null when neither supplies a valid one, and readiness then answers 503; never the start time.
-
node_versionstring requiredThe Node.js version (process.version).
TrialCreateSessionRequest
no additional properties
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object requiredmin items 1 · max items 100
-
typestring requiredmin length 1 · max length 64
-
-
-
actionsarray of object requiredmin items 1 · max items 5
no additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"optionalOne accepted response per revision (the only P1 policy; the default).
-
TrialCreateSessionResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
revisioninteger requiredminimum 1
-
human_urlstring requiredThe human link (a capability): share it only with the responder.
-
workspace_idstring requiredThe trial workspace this Session belongs to.
-
management_credentialstring optionalReturned once, only when this request created the trial (no Authorization header). It reads this trial’s results and creates further Sessions in it; it is never retrievable again. Keep it secret; never put it in a URL.
pattern
^sess_mg_[A-Za-z0-9_-]{43}$ -
action_expires_atstring requiredAfter this instant the human link accepts no response.
-
result_available_untilstring requiredUntil this instant the result can be read with the management credential.
-
trial_expires_atstring requiredAfter this instant the trial creates no further Session.
TrialSessionResponse
no additional properties
-
idstring requiredpattern
^ses_[0-9A-HJKMNP-TV-Z]{26}$ -
status"active"or"responded"or"completed"required -
revisioninteger requiredThe current Surface revision.
minimum 1
-
interactionobject requiredno additional properties
-
mode"interactive"required -
titlestring requiredmin length 1 · max length 200 · pattern
\S -
descriptionstring optionalmax length 4000
-
sourceobject requiredno additional properties
-
kind"sess_surface"required -
componentsarray of object or object or object or object required
-
-
actionsarray of object requiredno additional properties
-
idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
labelstring requiredmin length 1 · max length 200 · pattern
\S -
intent"submit"or"continue"or"approve"or"reject"or"request_change"optional
-
-
response_policy"first"required
-
-
response_schemaobject requiredThe JSON Schema 2020-12 the current revision’s responses are validated against.
-
responsesarray of object requiredEvery accepted response, in sequence order, each bound to its revision.
no additional properties
-
event_idstring requiredpattern
^evt_[0-9A-HJKMNP-TV-Z]{26}$ -
sequenceinteger requiredMonotonic per-Session Event sequence.
minimum 1
-
revisioninteger requiredThe Surface revision it was accepted on.
minimum 1
-
action_idstring requiredpattern
^[a-z][a-z0-9_]{0,31}$ -
dataobject requiredThe normalized typed result, valid against that revision’s response_schema.
-
actorobject requiredno additional properties
-
assurance"link_holder"required
-
-
accepted_atstring requiredISO 8601 UTC time of acceptance.
-
receiptstring or null requiredThe signed decision receipt: a compact JWS (EdDSA/Ed25519, typ sess-receipt+jwt, kid) over the RFC 8785 canonical claims, verifiable with GET /.well-known/sess-receipt-keys.json. Issued once in the acceptance transaction and never re-signed. Its exp is at least 720 hours after acceptance and, for an owner-key Session that is purged automatically, no earlier than the Session’s latest possible purge (its human link’s expiry plus its retention after it ends). null only for responses accepted before receipts existed.
-
-
trialobject requiredno additional properties
-
workspace_idstring required -
action_expires_atstring requiredAfter this instant the human link accepts no response.
-
result_available_untilstring requiredUntil this instant this result remains readable.
-
EmailLinkRequest
no additional properties
-
emailstring requiredThe address to send a sign-in link to. Trimmed and lower-cased.
min length 3 · max length 254
EmailLinkAccepted
no additional properties
-
status"accepted"requiredThe link was handed to the email provider. The same answer for every address: it never says whether an account exists.