Setting a webhook
Set the webhook URL on one of your numbers:url is required and must be https://. Every call on that number — inbound, outbound, or batch — will POST to it.
Read the current URL (returned in full, since it is your own endpoint), or DELETE to remove it:
Second webhook URL (optional)
Each number can have a second webhook URL in addition to the primary one. Both URLs receive the same payload, for both events (call.started and call.completed). Use it to send call data to a second endpoint — for example, your own system alongside a primary destination.
The second URL is API-only (there is no dashboard field for it). It mirrors the primary webhook routes, using webhook2 in the path:
url is required and must be https://. The primary webhook (set via /webhook/number/) is unaffected — the two URLs are independent. A number with both set delivers to both; with only one set, only that one fires.
Payload structure
The body is a flat JSON object — every field is at the top level (no nestedcall wrapper). Only a curated, whitelisted set of fields is sent; internal data (your system prompt, API key id, database ids) is never included.
Key fields
Call recordings are stored in your Nixflex backend and delivered via
recording_url. They are not retained on your telephony provider’s servers - Nixflex saves its own copy and removes the provider’s copy after download. For long-term storage, save the file from recording_url into your own backend when you receive the webhook.Appointment bookings
If the agent books, reschedules, or cancels an appointment during a call (via a connected calendar), each action is captured as a structured object in thebookings array. This is the reliable way to know an appointment changed — read it directly instead of parsing the transcript or summary.
The array is per call: every booking action taken on that one call is listed, in order. A call with no booking activity sends bookings: [].
Bookings are also stored on the call record, so if a webhook delivery is missed you can still fetch them later via the call’s API record — they are never lost.
Event types
Theevent field tells you which event the payload represents:
call.started— fires when a call connects, about 2 seconds after it begins. Use it for live tracking (a call just started on one of your numbers). Only the early fields are populated:event,call_id,agent_id,direction,from,to,status, andstarted_at. The post-call fields (transcript,summary,sentiment,successful,extracted,recording_url,duration_seconds,ended_at,avg_latency_ms) arenull, andbookingsis an empty array, because the call has not happened yet.call.completed— fires about 60 seconds after a call ends, with the full payload (transcript, summary, recording, bookings, and analysis).webhook.test— sent by the dashboard “Test” button so you can verify reachability. Not a real call.
call.started and call.completed are delivered to the same webhook URL. Switch on the event field to tell them apart. call.started uses the same delivery, retry, and logging as call.completed.
Signing and verification
Every webhook request includes a signature header so you can verify it came from Nixflex:<timestamp>.<raw_body> using the API key secret (key_secret) tied to the call’s API key as the signing secret.
Your key_secret is the part of your API key after the colon. API keys are formatted nxf_<id>:nxfs_<secret>, so the signing secret is the nxfs_... half only (not the full key, and not the nxf_ id).
If signature generation fails on our side, the webhook is still delivered without the
X-Nixflex-Signature header (delivery is never blocked). Treat a missing signature header as unsigned and skip verification for that request rather than erroring.Verifying in Node.js
Always use the raw request body bytes when computing the HMAC. If your framework parses JSON before you see it (Express body-parser does this by default), you’ll get a signature mismatch. Use
express.raw() middleware on the webhook route.Delivery and retries
The webhook fires roughly 60 seconds after the call ends — this gives Nixflex time to upload the recording, run post-call analysis, and include everything in one payload. The worker fetches fresh call data at fire time, sorecording_url and analysis fields are always current.
1
2xx or 3xx response
Delivered. No retry.
2
4xx (except 408, 429)
Treated as a permanent failure — your endpoint has a bug or rejected the request. No retry.
3
5xx, 408, 429, or timeout/network error
Retried automatically. Backoff between attempts: 5 min, 5 min, 5 min, 60 min (5 attempts total over ~76 min).
4
After 5 failed attempts
Given up. Logged in your dashboard so you can investigate.
Viewing delivery history
Go to Logs → Webhooks in your dashboard. Every delivery is logged with status, HTTP code, attempt count, last attempt time, the URL, and any error message. The last 5,000 successful and 5,000 failed deliveries are retained.Idempotency
The same call may arrive twice if a retry succeeds after the original was actually delivered (rare but possible). Store thecall_id from each payload and skip if you’ve already processed it.
Connecting to Zapier / Make
Both platforms support generic webhook triggers. Point them at the URL Zapier/Make gives you, and every call becomes a trigger. Because the payload is flat, fields map cleanly — you’ll seeSummary, Transcript, Sentiment, Duration Seconds, etc. directly, with no Call Call ... prefixes. From there, send data to Google Sheets, HubSpot, Salesforce, GoHighLevel, Slack, Notion, Airtable, email, or anything else those platforms support.
Testing your webhook
In the dashboard, go to Integrations → Webhooks, pick the number, and click Test. Nixflex sends a smallwebhook.test payload to that number’s URL and shows the HTTP status and response time. This only checks that your endpoint is reachable — it does not send a full call payload.