Guide
Integrate the call center into your software
Click to call from your software, show the caller when a call comes in, keep call history, recordings and summaries. About 30 minutes to a working version.
1Create an API key with call permissions
In the app: Settings › Apps & API › API keys → Call group → enable
call.partner.originate(dial on behalf),call.partner.calls_view(read call status),call.partner.agent_status(agent availability),call.recordings.view(recording links). Restrict Call agents this key may act for if the key serves one team only.2Click to call from your software
The agent’s phone is answered automatically (Gym Master softphone), then the customer is dialed — just like the agent clicking Call. Pick the agent with exactly one of
agentId,agentEmail,extension. The customer number can be written any way, results are always E.164. Send anIdempotency-Keyso a double click never places two calls. Put your own customer id incontactRef.curlcurl -X POST "https://api.nextx.vn/api/v1/call/partner/calls" \ -H "X-Api-Key: <API_KEY>" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 6f1c2b0e-0a7d-4e4f-9b1a-2f3c4d5e6f70" \ -d '{ "agentEmail": "[email protected]", "to": "0901234567", "contactRef": "CUS-00123", "metadata": { "ticket": "T-889" } }' # 201 → { "callId": "…", "status": "initiated", "to": "+84901234567", "agent": { … } }3Subscribe to Call webhooks and verify signatures
Settings › Apps & API › Webhooks → Call → paste the URL → Verify and save → enable the events you need. Signatures follow Standard Webhooks: use
verifyWebhookfrom@nextxai/sdk/webhooks(Node) orverify_webhookfromnextx_sdk.webhooks(Python); other languages use thestandardwebhookslibrary (Go, PHP, Java, C#…). Pass the raw body, not parsed JSON. Return2xxwithin 5 seconds and queue heavy work.Node.js (Express)import { Webhook } from "standardwebhooks"; // npm i standardwebhooks const wh = new Webhook(process.env.NEXTX_WEBHOOK_SECRET); // "whsec_…" app.post("/hooks/call", express.raw({ type: "application/json" }), (req, res) => { const raw = req.body.toString("utf8"); const event = JSON.parse(raw); // the URL verification ping uses a one-time secret: answer it BEFORE checking the signature if (event.type === "endpoint.verification") return res.json({ challenge: event.challenge }); try { wh.verify(raw, req.headers); // webhook-id / webhook-timestamp / webhook-signature } catch { return res.sendStatus(401); } queue.add(event); // handle it in the background res.sendStatus(200); });4Incoming call popup and call history
call.ringingarrives while the customer is calling: look them up byfromand show the popup.call.completed/call.missedcarry the final status (completed,busy,no-answer,failed,canceled,abandoned) and a Q.850hangupCause. Webhooks may arrive more than once or out of order: de-duplicate byid, re-order bysequence.workerasync function handle(event) { if (await db.processed.exists(event.id)) return; // delivered at least once const call = event.data.object; // callId, status, from, to (E.164), agent, sequence… if (call.sequence < (await db.callSequence(call.callId))) return; // a later stage already arrived switch (event.type) { case "call.ringing": showPopup(call.agent?.email, await customers.findByPhone(call.from)); break; case "call.answered": markInProgress(call.contactRef, call.agent); break; case "call.completed": case "call.missed": saveCallLog(call.contactRef, call.status, call.talkSec, call.hangupCause); break; } await db.processed.insert(event.id); }5Recordings and summaries
On
call.recording_ready, call the API for a download link valid for 15 minutes (webhooks never contain the link). Oncall.summary_ready, read the call summary.curl# on call.recording_ready — the link is valid for 15 minutes, ask again when it expires curl "https://api.nextx.vn/api/v1/call/partner/calls/<callId>/recording" \ -H "X-Api-Key: <API_KEY>" # → { "url": "https://…", "expiresAt": "…", "contentType": "audio/wav" } # on call.summary_ready curl "https://api.nextx.vn/api/v1/call/calls/<callId>/summary" -H "X-Api-Key: <API_KEY>"6Try it on sandbox
Use
to=sandbox:echo: the agent rings, after answering they hear a test tone for about 10 seconds, then the call ends without reaching any carrier. You receive the full webhook sequence like a real call. Each key may place up to 60 calls per minute.curl (sandbox)curl -X POST "<SANDBOX_API_URL>/api/v1/call/partner/calls" \ -H "X-Api-Key: <SANDBOX_API_KEY>" -H "Content-Type: application/json" \ -d '{ "extension": "1021", "to": "sandbox:echo", "contactRef": "TEST-1" }'