talkpilot-shared/docs/webhook-samples/, kept in
sync by a test), so what you see here is what arrives.
Configuration
Post-call URL — setpost_call_webhook_url on the agent; both call_started and call_ended
are delivered there:
Pre-call request
Sent before the agent greets the caller. Use it to look the caller up in your CRM and hand the agent variables for its prompt and greeting ({{var.name}}), or to route the call to another agent.
Request body:
200 and JSON within 3 seconds. Two shapes are accepted:
variables/dynamic_variables— become{{var.<name>}}in prompt and greeting and are echoed back aspre_call_variablesin both events below.agent_id/override_agent_id— optional: the UUID of another agent of your organization that should take the call instead.
call_started
Sent once the call is set up, before the first sentence. No retries — treat it as a hint, not as a
guarantee.
call_ended
Sent after the call ends, with the full transcript.
Transcript entries
arguments and content are JSON encoded as strings — parse them a second time if you need the fields.
A user entry with ignored: true is not part of the conversation with the agent — the agent
discarded the line, its language model never saw it. ignored_reason says why:
during_greeting — spoken in the short pause before the greeting and discarded, usually before
the recording starts; during_transfer — picked up during or after a transfer. More reasons may
follow, so treat any unknown value as ignored as well. To show only the conversation with the
agent (for example in a CRM note or a summary), skip these entries. total_turns counts them.
The webhook carries the raw call. The customer name, request and summary you see in the Dashboard
are produced afterwards by post-processing; fetch them with the Calls API if you need them.
Verifying the signature
Every delivery is signed when TalkPilot has a webhook secret configured for your account (ask support for it). Headers:
Verify over the raw request body exactly as received. The body is serialized deterministically
(keys sorted, no whitespace, UTF-8 not escaped), so re-serializing a parsed payload the same way
also works, but the raw body is the safe choice.
signature_vector.json in the samples): with secret beispiel-webhook-secret,
timestamp 1788776142 and the call_ended payload above serialized canonically, the signature is
sha256=8470225fe8cb45c069f89a9eea963b3702764a670e542b314094ef57167d3525.
Best practices
- Respond with 200 quickly — process asynchronously;
call_endedwaits at most 10 seconds per attempt. - Deduplicate on
call_id—call_endedis retried up to three times, so a delivery can arrive twice. - Verify the signature instead of relying on a secret in the URL.
- Catch up via the API — if your endpoint was down for all attempts, the delivery is lost; use the Calls API to backfill.
- Don’t rely on
call_startedfor anything critical — it is not retried.
Related resources
- Agents API — Configure
post_call_webhook_url - CRM Integration — End-to-end integration guide