Webhooks and guides
Webhooks: results pushed to you
Get a signed POST to your server every time a call ends, and check the signature.
Turn it on
- For every call: in Nerro, open Connectors, choose Outgoing webhook and enter your URL.
- For one employee's calls only: open the employee and fill in Webhook URL.
Each has its own signing secret, which an owner or admin can show or replace.
What we send
A POST with a JSON body, every time a call ends:
{
"event": "call.ended",
"callId": "c1d2…",
"employeeId": "8f0c…",
"employeeName": "Ava",
"outcome": "appointment_booked",
"summary": "Caller booked a showing for 12 Elm St on Thursday at 4 PM.",
"startedAt": "2026-11-02T15:04:05.000Z",
"callerNumber": "+13125550142"
}The Send test button sends the same shape with "event": "test". For the full call, look it up with GET /calls.
Check the signature
Every delivery carries x-nerro-timestamp (milliseconds) and x-nerro-signature: sha256= and the HMAC-SHA256, in hex, of the timestamp, a dot and the raw body, keyed with your signing secret.
import { createHmac, timingSafeEqual } from "node:crypto";
function fromNerro(rawBody, headers, secret) {
const ts = headers["x-nerro-timestamp"];
const expected = "sha256=" + createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex");
const got = headers["x-nerro-signature"] ?? "";
const fresh = Math.abs(Date.now() - Number(ts)) < 5 * 60 * 1000;
return fresh && got.length === expected.length && timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}Check the raw body as it arrived, before parsing it.
Answering and retries
Answer with any 2xx within 8 seconds. If your server is down, times out or answers 408, 429 or 5xx, Nerro tries again, starting 30 seconds later, up to 4 times. Other 4xx answers aren't retried. Redirects aren't followed, and addresses inside private networks are refused. Use the call's callId to ignore a delivery you've already handled.
Still stuck? Email support@nerro.si. A person replies within 24 business hours.
