Webhook event types
Complete request envelope, message payload, control payload and signature headers delivered to your receiver.
AgentBrains sends an HTTPS POST with a JSON body to your subscription URL. Your receiver handles two version-1 event types. Each body has the following shape. Property names ending in ? are optional. Other properties are required.
type Sender = {
type: "customer" | "ai" | "human" | "system" | "unknown";
external_id?: string;
};
type MessageData = {
message_id: string;
body: string;
direction: "incoming" | "outgoing";
sender: Sender;
created_at: string;
client_message_id?: string;
};
type ControlData = {
previous_mode: "ai" | "human";
mode: "ai" | "human";
control_version: number;
};
type EventEnvelope = {
id: string;
version: 1;
occurred_at: string;
tenant_id: string;
employee_id: string;
conversation_id: string;
recipient_id: string;
channel: "web-chat" | "email";
sequence: number;
is_test: boolean;
};
type WebhookEvent =
| (EventEnvelope & {
type: "message.created";
data: MessageData;
})
| (EventEnvelope & {
type: "conversation.control_changed";
data: ControlData;
});Envelope fields
| Field | Type and meaning |
|---|---|
id | Nonempty string identifying this event. Stable across retries. Deduplicate using this field. |
type | Literal message.created or conversation.control_changed. Selects the corresponding data type. |
version | Integer literal 1. |
occurred_at | RFC 3339 UTC timestamp string. |
tenant_id | Workspace ID bound to the subscription. |
employee_id | Employee expertId associated with the campaign. |
conversation_id | ID of the conversation that produced the event. |
recipient_id | ID of the associated recipient. |
channel | Literal web-chat or email. |
sequence | Positive integer allocated per conversation, shared across both event types. Deliveries can arrive out of order. |
is_test | Boolean indicating synthetic QA activity. External subscriptions exclude events marked true. |
Message payload
| Field | Type and meaning |
|---|---|
message_id | Nonempty stored message ID. Use it to merge this event with structured history. |
body | Nonempty stored text. |
direction | Literal incoming or outgoing. |
sender.type | Literal customer, ai, human, system or unknown. |
sender.external_id | Optional nonempty string, up to 255 characters. External operator identity supplied by the integration. |
created_at | Message persistence timestamp as an RFC 3339 UTC string. |
client_message_id | Optional nonempty string, up to 255 characters. Included for an operator command. |
message.created reports persistence. Its body has no customer delivery status. Use the structured message returned by the operator endpoint or history to inspect delivery_status.
Control payload
| Field | Type and meaning |
|---|---|
previous_mode | Literal ai or human before the transition. |
mode | Literal ai or human after the transition. |
control_version | Positive integer after the transition. Pass it as expected_version for the next change. |
A request that repeats the current mode produces no new control event.
Delivery headers
| Header | Type and meaning |
|---|---|
Content-Type | application/json. |
X-AgentBrains-Event-Id | Same string as body id. |
X-AgentBrains-Timestamp | Decimal Unix timestamp in seconds for this HTTP attempt. |
X-AgentBrains-Signature | v1= followed by the hex HMAC-SHA256 of <timestamp>.<raw body>. |
Verify the signature over the raw UTF-8 bytes using the literal signing-secret string. Compare in constant time and reject timestamps outside five minutes. Signatures and delivery timestamps change on retry. Event IDs and bodies remain stable.
Receiver responses
Return any HTTP 2xx after durable acceptance. Network failures, 408, 429 and 5xx are retried for up to 24 hours. A 410 response disables the subscription. Redirects and other non-retryable HTTP responses end that delivery attempt series.
See the conversation integration guide for processing order, history synchronization and the full test flow.
Send operator message
Accept an idempotent operator reply for an active web chat in human mode. A 202 response reports acceptance. Required scope: `conversations:write`.
Create webhook subscription
Create a subscription for new matching events. Save signing_secret from the response once. Required scope: `webhooks:manage`.