Webhooks setup
To set up webhooks, go to Settings > Webhooks in the Dashboard and add the URLs you would like to receive events on. A company can configure multiple active webhook URLs; leaving the list empty disables delivery. When a webhook is created, a signing secret is automatically generated. Every dispatch is signed with HMAC-SHA256 using that secret — you can verify the signature on your server to confirm the request originated from Olimi and that the payload wasn’t tampered with.When a webhook fires
A webhook is sent once per call, after the AI summary pipeline finishes for that call. Specifically:- The call must have a transcript with at least one user message (calls with no user messages are summarized as “No message was left during this call.”).
- The company must have at least one active webhook configured.
- Delivery is asynchronous and queued — the webhook is dispatched after the call record is committed to the database.
Request format
The body is a plain JSON object — not a JSON:API envelope. Treat unknown fields as additive; new fields may be introduced without a breaking change.
Signing secret
Each webhook has awhsec_ signing secret (48 hex characters). The full secret is shown only on create or rotate — copy it immediately. All other API responses return a masked hint (whsec_…XXXX).
From Settings > Webhooks use the rotate (↻) and revoke (🗑) icons to manage the secret, or via the API:
POST /api/v2/organization-webhooks/:id/rotate-token— generates a new secret; old one is immediately invalidatedDELETE /api/v2/organization-webhooks/:id/token— clears the secret; dispatches will send no signature headers until rotated
Signature verification
When a webhook has a signing secret configured, every outbound request includes two headers:X-Olimi-Timestamp— the Unix timestamp (seconds) at the time of dispatchX-Olimi-Signature—sha256=followed by the lowercase hex HMAC-SHA256 digest
How the signature is constructed
The signed message is formed by concatenating the timestamp, a dot, and the raw JSON body:Why HMAC over a Bearer token
With a raw Bearer token, your server compares the incoming header value to a stored secret — the secret itself travels in every request. With HMAC, the secret never leaves your server. You recompute the expected signature from the payload and timestamp, then compare — so even if a request is intercepted in transit, the secret cannot be extracted from it.Verifying in Node.js
Verifying in Python
Example headers
Payload
Field reference
Call outcome fields
call_status is one of:
is_final tells you whether to expect more. More than one webhook can arrive
for the same contact — each attempt is delivered as its own call with its own id.
answered— final, unless a callback was scheduled during the conversation, in which casecallback_datecarries the UTC time of the follow-up andis_finalisfalse.not_answered/failed— final only when no campaign retry remains. If the campaign will dial again,is_finalisfalse.pending/in_progress— never final.
is_final: true as the signal to close the record on your side; earlier
deliveries are interim updates for the same contact.
Transcript items
Each transcript item includes detailed metadata and execution flags:system, assistant, user.
Custom keys
Each custom key is an object withkey and value:
callback_date key, when present, is also consumed server-side to schedule a callback on the contact — you don’t need to act on it unless you want to mirror the behavior in your own system.
Campaign
Included only when the call belongs to a campaign.Example payload
is_final is false in this example because the conversation scheduled a callback —
callback_date carries its UTC time, and a further webhook will follow that call.Receiver expectations
- Respond with any
2xxstatus to acknowledge receipt. Non-2xx responses trigger retries on our end. - Your endpoint must accept
application/jsonrequest bodies. - Don’t rely on JSON key ordering — it is not guaranteed.
durationis in seconds.call_timeandcallback_dateare ISO-8601 in UTC.- Expect more than one webhook per contact. Key your records off
id(unique per call attempt) and useis_finalto decide when the outcome is settled. - Treat unknown fields as additive and ignore them if you don’t need them.