Skip to main content

Event catalog

Section: DOC-IN-webhooks-events#event-catalog.

This reference defines outgoing webhook payloads, delivery headers and signature verification. Each event below has a dedicated schema and example page. Start with Receive a completed order summary to build the customer workflow, or Recover a missing backend update to investigate a delivery. Conversation streaming has a separate contract.

Webhook events​

Section: DOC-IN-webhooks-events#webhook-events.

Webhook events are delivered as HTTP POST requests to the endpoints and subscriptions you manage via the Webhook APIs.

Delivery envelope​

Section: DOC-IN-webhooks-events#delivery-envelope.

The request body is the event payload itself — there is no wrapper object. The body's top-level keys are the payload fields listed under Payload shapes (event_context plus the event's own fields), encoded as JSON with snake_case names — this differs from the camelCase used by API responses.

The table and example below describe the documented timestamped-signature format. Confirm the actual header and signing configuration for your deployed endpoint before relying on it. The signed body contains the authoritative event_context.event_name and event_context.event_id; separate routing and deduplication headers are not covered by the documented body HMAC:

HeaderDescription
X-Convoy-Event-TypeThe event type string, e.g. llm.message_published
X-Convoy-Idempotency-Key{event_id}:{endpoint_id} — check against signed body identity and your configured endpoint before use
X-Convoy-Signaturet={unix_seconds},v1={hex} — see the verification procedure below

An illustrative llm.message_published delivery in this format looks like this:

POST /your-endpoint HTTP/1.1
Content-Type: application/json
X-Convoy-Event-Type: llm.message_published
X-Convoy-Idempotency-Key: d3b842c8-b19a-4205-a06f-c57cbf313582:01M0FJHPDVYYBA1V856RK6K91P
X-Convoy-Signature: t=1787229727,v1=050d3756a2953051bfb045490398894546c0d1a7c6fdf3c09d206fdeeeb92255

{
"event_context": { "event_name": "llm.message_published", "event_id": "d3b842c8-b19a-4205-a06f-c57cbf313582", "...": "..." },
"message": { "...": "..." }
}

After verifying the signature, route by signed event_context.event_name and validate the expected schema and scope. Reject disagreement with X-Convoy-Event-Type. Derive deduplication from signed event_context.event_id, your configured endpoint and payload digest; reject a conflicting idempotency header. A valid body signature does not authenticate arbitrary header replacements.

Verify the signature before processing the payload. The signing secret is the value returned in the secret field when you call list-endpoints for the receiving endpoint.

In this format, t is the signing time in Unix seconds. v1 is the hex-encoded HMAC-SHA256 of the string {t},{raw_body} — the timestamp, a comma, then the raw request body — computed with the per-endpoint secret. Two details matter and are easy to get wrong: the signed input is not the body alone, and the digest is hex, not base64.

Verify it before processing the payload. A missing or invalid signature cannot establish the sender's authenticity; reject the request and inspect the endpoint's configured format and secret through an authorized channel.

Use a verifier compatible with the signature format above, or implement all of these checks:

  1. Bound header/body size and the number of signature fields. Parse safely; missing separators, invalid integers, repeated timestamp fields and malformed hex must reject without raising an unhandled error.
  2. Require one signing timestamp and at least one supported version signature. Preserve multiple v1 values during key rotation instead of overwriting them in a dictionary.
  3. Enforce a bounded timestamp tolerance (five minutes is an example receiver setting), with an explicit clock-skew policy.
  4. Compute HMAC-SHA256 over the original timestamp text, a comma and the raw body bytes. Compare equal-length decoded digests in constant time against the small configured set of current/overlap secrets. Never log those secrets or the signature.
  5. After verification, enforce the expected scope and event schema. Derive type and event identity from signed event_context.event_name and event_context.event_id, bound to your configured endpoint. Reject conflicting type/idempotency headers: those separate headers are not covered by the body HMAC. Atomically persist the scoped event identity, payload digest and pending work before acknowledging. The timestamp tolerance limits old replays; it does not prevent duplicates within the window.

Pass the raw request body bytes, exactly as received. Re-serializing the parsed JSON changes the bytes (key order, whitespace) and the signature will not match.

Five minutes is an example receiver tolerance, not a platform-imposed acceptance window. Choose and enforce a bounded policy appropriate to the receiver’s clock skew.

Secret rotation: the current public update-endpoint operation changes the endpoint's name, URL and description. It does not accept a secret field, and there is no public secret-rotation operation. Do not use an endpoint-metadata update as evidence that a signing key changed. Qualify any separately supported rotation procedure for your deployment, including receiver overlap and signatures on new and retried deliveries, before relying on it.

Event types​

Section: DOC-IN-webhooks-events#event-types.

EventOwnerDirectionEmitted when
llm.message_publishedConversationsTravila → your endpoint (outgoing)An assistant/tool message is produced or an assistant message snapshot is updated.
llm.generation_startedConversationsTravila → your endpoint (outgoing)A generation run starts for a conversation.
llm.generation_completedConversationsTravila → your endpoint (outgoing)A generation run reaches a terminal outcome. Inspect status and correlate run_id.
llm.tool_call_startedDelegation and approvalsTravila → your endpoint (outgoing)A tool call is dispatched for platform or client execution.
llm.tool_call_approval_requiredDelegation and approvalsTravila → your endpoint (outgoing)A routed tool call is parked for human approval with a decision deadline.
llm.tool_call_completedDelegation and approvalsTravila → your endpoint (outgoing)A tool call reaches a terminal outcome, including a rejected or timed-out approval.

Subscribe only to what you act on. llm.message_published and llm.generation_completed can both concern a normal assistant turn. Give them distinct lifecycle handlers and correlate their identities so they do not trigger the same business action twice.

Payload shapes​

Section: DOC-IN-webhooks-events#payload-shapes.

Payload field names use snake_case.

llm.message_published​

Section: DOC-IN-webhooks-events#llmmessage_published.

See llm.message_published payload, example and producing operations.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
messageMessageOptionalThe generated assistant/tool message

Full payload: LLMMessagePublishedEvent.

llm.generation_started​

Section: DOC-IN-webhooks-events#llmgeneration_started.

See llm.generation_started payload, example and producing operations.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
run_idstringOptionalUnique identifier for the workflow run
configGenerationConfigOptionalOptional snapshot of generation configuration used for this run
starting_sequencestring (int64)OptionalConversation sequence number at the moment the run started (if known) Pattern: ^-?\d+$.

Full payload: LLMGenerationStartedEvent.

llm.generation_completed​

Section: DOC-IN-webhooks-events#llmgeneration_completed.

See llm.generation_completed payload, example and producing operations.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
run_idstringOptionalUnique identifier for the workflow run
statusstring (WORKFLOW_STATUS_RUNNING, WORKFLOW_STATUS_COMPLETED, WORKFLOW_STATUS_FAILED, WORKFLOW_STATUS_TIMED_OUT, WORKFLOW_STATUS_CANCELED) or integer (int32)OptionalTerminal status of the run
loop_countinteger (int32)OptionalNumber of agent loops/steps executed Minimum: -2147483648. Maximum: 2147483647.
duration_msstring (int64)OptionalEnd-to-end run duration in milliseconds Pattern: ^-?\d+$.
usageUsageOptionalOptional usage accounting for the run
errorRpcErrorOptionalStructured error for FAILED/TIMED_OUT/CANCELED runs.
usage_by_modelArray of UsageByModelOptionalPer-model breakdown of the same usage usage aggregates. Additive: usage stays the run-level total so existing consumers are unaffected, while billing keys its charges on model. Empty when the producer predates it.
turn_keystringOptionalIdentifies the conversation turn this run served: the message_id of the opening user message, resolved once at run start and stamped on every message the run emits as Message.source_user_message_id. Empty when the producer predates this field, or when the turn is unresolvable — never guess one, an empty key means "no turn attribution".
Values of status​

Lifecycle state of a workflow execution, distinct from the reason a terminal execution ended.

ValueNo.FormMeaning
WORKFLOW_STATUS_RUNNING1CanonicalThe workflow has started and has not reached a terminal outcome.
WORKFLOW_STATUS_COMPLETED2CanonicalThe workflow finished successfully.
WORKFLOW_STATUS_FAILED3CanonicalThe workflow ended because execution failed; inspect its error or end reason.
WORKFLOW_STATUS_TIMED_OUT4CanonicalThe workflow ended because its execution time limit elapsed.
WORKFLOW_STATUS_CANCELED5CanonicalThe workflow was cancelled before normal completion. This enum retains its existing CANCELED wire spelling.

Full payload: LLMGenerationCompletedEvent.

llm.tool_call_started​

Section: DOC-IN-webhooks-events#llmtool_call_started.

See llm.tool_call_started payload, example and producing operations.

Fires when a tool call is dispatched — both for tools the platform runs itself and for client-side tools, which are dispatched to you.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
tool_callToolCallOptionalTool-call snapshot before a result is available, including its identity, name, server and arguments. For llm.tool_call_started the status is EXECUTING; for llm.tool_call_approval_required it is REQUIRES_CONFIRMATION and requires_approval_at is the decision deadline. result_json is unset.

Full payload: ToolCallStartedEvent.

tool_call.status is always TOOL_EXECUTION_STATUS_EXECUTING here: the event says what was dispatched, not what came back.

For a client-side tool the run is parked on you from this moment, exactly as llm.tool_call_approval_required parks it on an approver. The payload does not carry a flag distinguishing the two kinds, so match on the tool names you declared in clientTools — those are the only ones you are expected to run. It also does not carry the answer deadline; read clientToolDeadlineAt from list-pending-client-tools when you need it.

llm.tool_call_completed​

Section: DOC-IN-webhooks-events#llmtool_call_completed.

See llm.tool_call_completed payload, example and producing operations.

Fires when a tool call reaches a terminal state — a result you submitted, a result the platform produced, or a timeout.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
tool_callToolCallOptionalFinal tool call: status is terminal (SUCCESS|FAILED|CANCELLED|TIMED_OUT), result_json populated.
execution_time_msinteger (int32)OptionalWall-clock execution time in milliseconds (0 when unknown, e.g. dispatch error). Minimum: -2147483648. Maximum: 2147483647.

Full payload: ToolCallCompletedEvent.

llm.tool_call_approval_required​

Section: DOC-IN-webhooks-events#llmtool_call_approval_required.

See llm.tool_call_approval_required payload, example and producing operations.

A routed tool call is waiting for human approval. This event uses the same native payload shape as llm.tool_call_started; the signed event name and tool-call status distinguish them. The call has TOOL_EXECUTION_STATUS_REQUIRES_CONFIRMATION and a requires_approval_at decision deadline.

Webhook JSON uses protobuf field names (snake_case).

FieldTypePresenceMeaning
event_contextEventContextOptionalEvent provenance and routing metadata associated with the emitted event.
tool_callToolCallOptionalTool-call snapshot before a result is available, including its identity, name, server and arguments. For llm.tool_call_started the status is EXECUTING; for llm.tool_call_approval_required it is REQUIRES_CONFIRMATION and requires_approval_at is the decision deadline. result_json is unset.

Full payload: ToolCallStartedEvent.

Use list-pending-approvals to reconcile calls awaiting a decision, and submit-tool-approvals to resolve them. A pending call waits for a decision or its deadline; other calls may proceed under the MIXED policy. Treat a missing deadline as unknown and decide promptly, rather than assuming the call can wait indefinitely.


Conversation updates​

Section: DOC-IN-webhooks-events#conversation-updates.

This catalog describes outgoing webhooks; it does not define an incoming-webhook endpoint. Scheduled callbacks send the payload configured on the schedule and use a separate signed-token protocol. They do not share these event payload schemas.

Conversation updates have separate delivery and recovery rules from webhooks. See streaming availability, event interpretation and reconnection requirements. Never substitute a conversation activity sequence for a message sequence or treat an idle conversation as proof that a particular run completed.

Document ID: DOC-IN-webhooks-events. Section identities and revisions.