Events
An endpoint receives only the events it subscribes to.
POST /tenants//webhooks
Register an endpoint. Required scope:settings:write
url must be publicly resolvable https. It is checked against an SSRF
guard (DNS resolved, private ranges refused) at registration.
The payload
input holds the fields your tool declared, under your field names.
channel is web, voice, api (an agent called the API) or form (the
standalone form widget).
messages — the conversation, when we already have it
The last 10 turns of the conversation that produced the submission, so you don’t
have to call back to find out what the visitor actually asked.
It is present when the turns are in memory at delivery time — the chat path.
It is absent for the form widget (channel: "form", there is no conversation)
and may be absent on other channels: we do not add a database read to a
fire-and-forget path that runs for every tool execution. Treat it as optional
and fall back to conversationId +
GET /tenants//conversations/
when you need the full thread.
Only user and assistant turns are included — never system prompts or tool
calls.
Keeping visitor PII off the wire
piiFields lists keys to remove from data.input before signing and sending —
for example ["visitorEmail", "visitorPhone"] if your CRM must not receive
contact details over this channel. Max 32 entries.
Setting any
piiFields also removes messages entirely. A transcript is
free text: the visitor typed their email into it, so redacting a key while
shipping the conversation verbatim would defeat the request. The unredacted
payload is still kept in our database for your audit trail — only the wire is
trimmed.Verifying the signature
Every request carries three headers:v1 is HMAC_SHA256(secret, "<t>.<raw request body>"), hex-encoded. Sign the
raw body — re-serializing your parsed JSON will not match.
Reject the request if |now - t| > 300 seconds: without that check, a captured
request can be replayed forever.
Delivery, retries and timeouts
Answer with any2xx and quickly: the request is aborted after 5 seconds.
Do the work after acknowledging, not before.
A non-2xx, a timeout or a connection error schedules a retry. Six attempts
total, spaced 30 s, 2 min, 10 min, 1 h, 6 h — about 8 hours of tolerance for
an endpoint that is down. After the last failure the delivery is marked failed
and stays inspectable.
Retries mean the same event can arrive twice (for instance if your 2xx was lost
on the way back). Deduplicate on X-Animam-Delivery-Id, or on data.id if you
prefer to key on the submission.
GET /tenants//webhooks
List endpoints. Secrets are never included. Scope:settings:read
GET /tenants//webhooks/
One endpoint, with its recent delivery stats. Scope:settings:read
PATCH /tenants//webhooks/
Changeurl, description, events, enabled or piiFields.
Scope: settings:write
Disabling an endpoint ("enabled": false) stops delivery immediately; deliveries
already pending are dropped rather than queued forever.
DELETE /tenants//webhooks/
Remove the endpoint and its delivery history. Scope:settings:write
GET /tenants//webhooks//deliveries
The delivery log: status, attempt count, HTTP status, last error, timestamps. This is where you look when your endpoint says nothing arrived. Scope:settings:read
POST /tenants//webhooks//deliveries//redeliver
Queue a past delivery again — same payload, freshly signed (the timestamp moves, so the old signature would not have verified anyway). Use it after fixing your receiver rather than asking a visitor to submit again. Scope:settings:write