Connect an inbound voice agent to an advanced phone system (PBX) such as 3CX. Your phone system can send caller context — like IVR menu selections — to the agent right before it bridges the call, and retrieve call results (telemetry plus values the agent collected) after the call ends.
agents:voice:manage permissionsequenceDiagram
participant C as Caller
participant P as Phone system (PBX)
participant K as KarmaFlow
participant A as Voice agent
C->>P: Dials in, makes IVR selections
P->>K: POST pre-call webhook (caller, IVR data)
P->>A: Bridges the call to the agent's number
K->>A: Injects the pre-call context into the agent
A->>A: Collects configured values during the call
A->>C: Ends the call (only after required values are saved)
P->>K: POST post-call webhook
K->>P: Call telemetry + collected values in the response
caller or call.from). KarmaFlow matches the webhook to the incoming call using this number.ivr.selectionIVR Selection{{ivr_selection}}When the call arrives, the mapped values appear to the agent as a "Phone system context" block, and any {{placeholder}} keys in the agent's instructions resolve to the received values. If no webhook arrives before the call, the call proceeds normally without the context.
Caller-ID mismatch: some phone systems bridge calls as a three-way call, so the caller ID KarmaFlow sees may differ from the number in the webhook payload. Leave Tolerate caller-ID mismatch on to accept the context anyway when exactly one pending context exists for the agent.
The agent saves values as the caller provides them. If it tries to end the call while required values are missing, the hang-up is refused and the agent is told what to ask for. If the caller hangs up first, the results are still delivered with valuesComplete: false and a missingRequired list.
Two delivery options — use either or both:
Your phone system pulls (recommended for 3CX-style flows). Turn on Post-call results — phone system pulls, save, and point your phone system's post-call HTTP step at the generated URL. When the PBX POSTs after the hangup, the response contains the results. If the call is still finalizing, the response is { "status": "pending" } — safe to retry the same request. Set Call ID field if your system echoes KarmaFlow's call ID back; otherwise matching falls back to the caller number.
KarmaFlow pushes. Turn on Post-call results — we push and enter your Destination URL. When a call ends, KarmaFlow POSTs the results, retrying on failure. Set a Signing secret (use Generate for a strong one) to receive an X-Karmaflow-Signature: sha256=<hex> header — the HMAC-SHA256 of <X-Karmaflow-Timestamp>.<body>. Add Static headers if your endpoint expects fixed headers such as an API key. Use Send test to deliver a sample payload to your endpoint (save the agent first).
The results payload looks like:
{
"event": "call.ended",
"callId": "…",
"direction": "inbound",
"from": "+15551234567",
"to": "+15557654321",
"startedAt": "2026-07-26T18:02:11.000Z",
"endedAt": "2026-07-26T18:06:40.000Z",
"durationSeconds": 269,
"disposition": "ended",
"collectedValues": { "ticket_number": "T-4821", "callback_ok": true },
"valuesComplete": true,
"missingRequired": [],
"recordingUrl": null
}
The AI call summary is produced by post-call analysis a few minutes after the call and is not included in this payload — review it on the call detail page.
200 with a contextId, that it fired before the call reached the agent's number, and that Caller number field points at the right payload path. Context expires after the configured lifetime (default 15 minutes).pending. The values are written as the call wraps up — retry after a second or two. If it persists, check the call actually ended on the call detail page.401 from a webhook URL. The URL token, header secret, or HMAC signature didn't match. Re-copy the URL (regenerating the token invalidates old URLs immediately) and verify the secret configured in your phone system.