CumulusDocs
Open Studio
On this page

Customer HTTP callbacks

Cumulus calls your application to execute a tool, obtain initial call context, deliver a lifecycle event or tokenize private keypad input. You host these endpoints in any language or framework. The example URLs below belong to a fictional customer application; choose your own paths and configure them through bindings and integrations.

The TypeScript server adapters implement these contracts. Customer HTTP adapters shows how to mount them. The payloads below let you implement the same endpoints in Python or another framework without installing the TypeScript SDK.

Configure and authenticate your endpoints

Expose a public HTTPS URL on port 443. Publish the tool or context action with its input/output schemas, deadline and pinned secret reference. Your application receives the matching secret bytes from your secret manager. Event destinations have their own signing secret and subscriptions.

Tool, context and vault adapters support these authentication choices. Use the same choice in the published binding and your receiver:

SchemeRequest header and verification
bearerAuthorization: Bearer <shared-secret>; compare with your configured secret.
headerA configured header, such as X-Customer-Token: <shared-secret>.
retell_signatureX-Retell-Signature: v=<unix-milliseconds>,d=<lowercase-hex-hmac>. Compute HMAC-SHA256 over the exact body bytes followed by the timestamp's ASCII bytes. The default freshness tolerance is five minutes.

The adapters require an explicit integration name and a secret of at least 16 characters. The integration name is receiver configuration, not a request field. Event signatures use the separate protocol described below and require at least 32 characters. Compare secrets and signatures in constant time. Verify signatures against the original bytes before parsing JSON.

Tool execution

For this example, publish a POST tool whose input requires a string topic and whose output requires a string guidance. Cumulus sends:

http
POST https://service.example.com/cumulus/tools/guide
Content-Type: application/json
Authorization: Bearer <shared-secret>
Idempotency-Key: 55555555-5555-4555-8555-555555555555
json
{
  "args": { "topic": "repair" },
  "call": {
    "call_id": "33333333-3333-4333-8333-333333333333",
    "run_id": "22222222-2222-4222-8222-222222222222",
    "agent_id": "service_guide",
    "metadata": { "request_source": "service_desk" }
  }
}

Return HTTP 200 with the declared output object directly:

json
{ "guidance": "Ask which equipment needs repair." }

call_id identifies the conversation; run_id identifies the run used by the runs API. They are different identities. agent_id identifies the agent, not its publication version. The SDK requires call_id and agent_id; run_id and metadata are optional in its envelope. Require a run ID in your application if an authorized run lookup is necessary. Metadata is application context, not proof of permission to access an account.

The Idempotency-Key identifies this tool effect. For effect_key tools it is required. Persist intent and outcome under your configured integration and this key. A duplicate with the same input should return the saved result; reject reuse with different input. The adapter validates the key's presence but does not deduplicate your work.

GET tools receive arguments as query parameters, without an args/call body:

http
GET https://service.example.com/cumulus/tools/guide?topic=repair
Authorization: Bearer <shared-secret>
Idempotency-Key: 55555555-5555-4555-8555-555555555555

String arguments remain strings; other argument values use JSON encoding in the query. Duplicate parameter names are invalid. GET adapter context has no conversation, run or agent identity, and empty metadata. Use GET for read-only work; none_read_only permits omission of the effect key.

Return before the tool's configured deadline, which can be 500–120,000 milliseconds. The SDK adapter uses that deadline and defaults to a 65,536-byte request limit, configurable with maxBodyBytes. Validate arguments before invoking business logic and validate the response against the published output schema. An invalid output after execution is an uncertain outcome.

Initial inbound context

Configure a dedicated phone POST context action, an effect_key policy and declared output variables. This endpoint runs before the agent begins speaking. Its body is the full event envelope below, without the tool's args wrapper:

http
POST https://service.example.com/cumulus/context
Content-Type: application/json
Authorization: Bearer <shared-secret>
Idempotency-Key: 66666666-6666-4666-8666-666666666666
json
{
  "event": "call_inbound",
  "call_inbound": {
    "agent_id": "service_guide",
    "agent_version": 1,
    "from_number": "+12025550123",
    "to_number": "+12025550124"
  }
}

Both phone numbers are fictional. agent_version is an integer identifying the selected publication. Return HTTP 200 with declared string variables:

json
{ "call_inbound": { "dynamic_variables": { "demo_channel": "phone" } } }

To reject the call, return HTTP 200 with:

json
{ "call_inbound": { "reject": true } }

Declare demo_channel in the integration's contextOutputs and the SDK adapter's variables allowlist. Return strings only, at most 4,096 characters per value. Do not replace system fields such as user_number or agent_id. An incoming number can select a candidate account; perform your business verification before exposing or changing its data.

The SDK's default deadline is three seconds, configurable with timeoutMs; the published context action must allow at most ten seconds. Its default request limit is 65,536 bytes. Preserve the effect identity for reconciliation: a lost response is uncertain, and Cumulus does not automatically resend an already-sent context effect. Invalid or missing required context can prevent agent startup.

Lifecycle events

Publish a notification destination with semantic.v1 format and subscriptions to run.admitted, run.ended, recording.updated or analysis.updated. Each POST contains one complete semantic event. For example:

http
POST https://service.example.com/cumulus/events
Content-Type: application/json
X-Talos-Event-Id: 44444444-4444-4444-8444-444444444444
Idempotency-Key: 44444444-4444-4444-8444-444444444444
X-Talos-Signature: t=<unix-seconds>,v1=<lowercase-hex-hmac>
json
{
  "owner_id": "talos",
  "environment": "test",
  "tenant_id": "11111111-1111-4111-8111-111111111111",
  "event_id": "44444444-4444-4444-8444-444444444444",
  "schema_version": 1,
  "subject": { "kind": "run", "id": "22222222-2222-4222-8222-222222222222" },
  "correlation_id": "22222222-2222-4222-8222-222222222222",
  "causation_id": null,
  "producer": "talos",
  "producer_version": "go-native-v2",
  "occurred_at": "2026-10-21T12:00:00.000Z",
  "privacy_class": "operational",
  "idempotency_key": "22222222-2222-4222-8222-222222222222:recording",
  "content": null,
  "run": {
    "run_id": "22222222-2222-4222-8222-222222222222",
    "attempt_id": null,
    "publication": {
      "agent_id": "service_guide",
      "version": 1,
      "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    }
  },
  "policy": null,
  "type": "recording.updated",
  "data": { "state": "not_required", "reason": "not_recorded" },
  "sequence": 1,
  "recorded_at": "2026-10-21T12:00:00.000Z"
}

Verify X-Talos-Signature by computing HMAC-SHA256 over the timestamp's ASCII bytes, a literal period (.), then the exact body bytes. The timestamp uses seconds; accept at most five minutes of clock difference by default. This differs from the millisecond tool signature above. Check the signature before trusting the payload, then validate the complete SemanticEvent schema.

Deduplicate the verified event_id. Both identity headers carry that ID; the body's idempotency_key is a separate event identity field and need not equal it. Durably save the event and any background-job intent before acknowledging. A successful SDK receiver returns HTTP 200:

json
{ "received": true }

Cumulus accepts a 2xx response and allows 20 seconds for delivery. A lost response is uncertain; notifications are not a guaranteed replay feed. Fetch current resources when reconciling missed work. Run end, recording and analysis are separate events; one does not establish another's readiness.

Accept up to 262,144 body bytes to cover the sender's event limit. With createEventHandler, set maxBodyBytes: 262144; its default is 65,536. The adapter awaits your consume callback before responding and does not impose its own processing deadline. Keep persistence inside the sender's 20-second window.

Private vault tokenization

Use a dedicated POST tool with purpose: 'tokenization', an effect_key policy, the declared private-field input schema and an authenticated vault binding. Configure the same tokenIdPath in the capture policy and receiver. Private workflows covers consent and keypad collection.

For an eight-digit synthetic reference and tokenIdPath: 'id':

http
POST https://vault.example.com/cumulus/tokenize
Content-Type: application/json
Authorization: Bearer <shared-secret>
Idempotency-Key: 77777777-7777-4777-8777-777777777777
json
{
  "args": { "reference": "87654321" },
  "call": {
    "call_id": "33333333-3333-4333-8333-333333333333",
    "run_id": "22222222-2222-4222-8222-222222222222",
    "agent_id": "service_guide",
    "metadata": {}
  }
}

Return HTTP 200 containing only the configured UUID token field:

json
{ "id": "9e89b3a8-a97a-41d1-9692-55832c5194ba" }

The dedicated SDK adapter accepts at most 16,384 request bytes and uses the tool deadline. It projects only the configured token field, including its nesting when tokenIdPath is dotted. An ordinary tool adapter refuses tokenization-purpose tools.

Deduplicate vault work durably by integration and effect ID. Keep raw digits and provider error payloads out of logs, traces and stored receipts. If the vault definitely refused and created no token, return HTTP 422 with { "error": { "code": "tokenization_declined" } } (TokenizationDeclined in the SDK). A timeout, malformed token or other error after invocation is uncertain: reconcile the original operation before creating another token.

Errors and replay

These are the SDK adapters' JSON responses; another framework should preserve the same status and outcome semantics:

Statuserror.codeMeaning
400invalid_tool_payloadInvalid contract input/identity, missing effect key or exceeded body limit; malformed tool, context or vault JSON.
401unauthenticatedAuthentication or signature freshness failed.
405method_not_allowedWrong HTTP method.
422tokenization_declinedVault definitely refused without creating a token.
500tool_outcome_uncertainDeadline, invalid post-execution output or uncertain vault outcome.
500tool_execution_failedOther handler failure; business work may already have occurred.

For example, invalid tool input returns:

json
{ "error": { "code": "invalid_tool_payload", "message": "Payload does not match the declared contract" } }

Cumulus treats ordinary tool 4xx responses as failed, except 408 and 429, which are uncertain. Non-2xx responses outside those definitive failures are also uncertain. An HTTP timeout does not undo a booking or vault write. Cumulus does not automatically resend an already-sent tool effect; retain your durable receipt so any reconciliation or duplicate request uses the original identity. See SDK errors and calls, results and events.

Content version f10231d9Customer SDKMarkdown source
Customer HTTP callbacks · Cumulus developer docs