Skip to main content
Set a webhook URL on a phone number and Nixflex will POST a clean, flat JSON payload to your server about 60 seconds after every call on that number ends. Use this to sync transcripts to your database, trigger downstream workflows, or pipe events into Zapier / Make. Webhooks are configured per phone number, so each number can send to its own endpoint.

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 nested call 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

The payload contains caller data — the caller’s phone number (from), the full transcript, and any extracted fields can include personal information. Store and process it in line with your own privacy policy and applicable law.
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 the bookings 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: [].
Because each action carries the booking_uid, you can mirror these straight into your own appointments table: insert on created, update on rescheduled, mark cancelled on cancelled. Drive your own confirmations and reminders from there.
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

The event 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, and started_at. The post-call fields (transcript, summary, sentiment, successful, extracted, recording_url, duration_seconds, ended_at, avg_latency_ms) are null, and bookings is 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.
Both 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:
The signature is HMAC-SHA256 of <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.
Always verify webhook signatures in production. Without verification, anyone who knows your URL could spam your endpoint with fake data.

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, so recording_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.
Request timeout is 10 seconds per attempt — keep your handler fast.

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 the call_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 see Summary, 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 small webhook.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.