The generic contract
The shape to send when no adapter fits your stack.
This is the shape to send when no adapter fits your stack. Both keyed endpoints read it, and a webhook can carry it too.
The two settings
| secret | Optional. An HMAC-SHA256 over the raw body, for the webhook path. With no secret set, the token in the URL is the only guard. |
|---|---|
| trust_sender_attribution | Default true. Set it false to ignore human-agent and platform-injected claims from the sender, so every turn your deployment produced is treated as the agent. |
With a secret set, send the digest as hex in an x-signature header. An x-hub-signature-256 header works too, and anything before an equals sign is ignored.
The event shape
One event is one JSON object. Send one, an array of them, or an object with an events array. Bulk import also reads one record per line.
json
{
"thread_id": "contact-4812",
"session_id": "call-99f1",
"type": "message.sent",
"ts": 1755820800000,
"payload": {
"role": "assistant",
"text": "Your order ships tomorrow."
},
"source": {
"platform_msg_id": "msg-7731",
"agent_version": "support-agent-3.2"
}
}| thread_id | Required. The conversation this belongs to, as your own system keys it. |
|---|---|
| session_id | Optional. One call or one chat inside that conversation. |
| type | Required. One of message.received, message.sent, tool.called, tool.result, call.started, call.ended, session.note. |
| ts | Required. Epoch milliseconds of when the message was created, never when you sent it to us. A value near 1.7e9 is seconds, and we refuse it. |
| source.platform_msg_id | Required. Your own id for this one event. |
| source.agent_version | Optional. Which build of the agent produced it. |
| payload.role | user, assistant or system. |
| payload.text | What was said. |
| payload.audio_ref | Where the recording is, for a voice turn. |
| payload.tool | For a tool event: name, call_id, arguments, result, error. |
A timestamp must fall between 2015 and 2100. An id is a string of at most 512 characters. One payload carries at most 5000 events.
What we do with sender attribution
Every turn your deployment produced is tagged, so a reply a person typed is never treated as the agent. An assistant turn is tagged as the agent, a system turn as platform injected, and a user turn is left alone.
You can say so per event with payload.source_tag, set to agent, platform_injected or human_agent. On a human_agent turn you can also send payload.operator_external_id and payload.operator_display_name, which name the person who replied. Send a work identity there, a staff email or a console user id, never a customer's own details.
Set trust_sender_attribution to false where you do not control the sender. A claim that excuses the agent, human_agent or platform_injected, is then dropped and the default stands. A claim that blames the agent is kept either way.
Read next
- Every word we use · The plain phrase for each idea in the product, and the formal name behind it.
- Dimensions and severity · The six things a check can be about, and the four levels of how much it matters.
- Platform matrix · All twelve platforms side by side: channel, audio, timestamps, delivery, retries.