Webhooks

Have every code POSTed to your server the moment it arrives, signed with your webhook secret, retried for about two hours.

Embed
Preview of the card
<a href="https://numestri.com/docs/webhooks"><img src="https://numestri.com/docs/_api/public/orgs/25229885-9620-4c08-bd2e-a0d0d74ac8b6/spaces/ef21e0c3-966d-4b03-b6d2-e66d449835d4/pages/a577a744-d654-4494-a354-6db95fcca821/social-card.svg?v=3e7ae33eec8b" alt="Webhooks" width="600" height="315"></a>

Add a webhook URL in the dashboard under Developer and every code is POSTed to it the moment it arrives — for one-time orders and for every message a rented number receives. HTTPS only.

What we send

POST /hooks/numestri HTTP/1.1
Content-Type: application/json
X-Numera-Event: sms.received
X-Numera-Signature: 9f2c1a…
X-Numera-Delivery: whk_8c1f…
X-Numera-Attempt: 1

{
  "orderid": "JRJ5UEXS",
  "sms": "140722",
  "full_sms": "140722 is your Telegram verification code.",
  "timestamp": "2026-10-14 07:42:11pm"
}

Header

Meaning

X-Numera-Event

sms.received or rental.received.

X-Numera-Signature

HMAC-SHA256 of the raw body, keyed with your webhook signing secret, in hex.

X-Numera-Delivery

The same on every retry of one notification — use it to ignore repeats.

X-Numera-Attempt

1 for the first try, then counts up.

Verify the signature

Your signing secret (whsec_…) is shown under Developer when you add the webhook. It is separate from your API keys, so keys can come and go without breaking verification. Check every delivery before trusting it:

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, signature, signingSecret) {
  const expected = createHmac("sha256", signingSecret).update(rawBody).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(signature ?? "", "hex");
  // Length first: timingSafeEqual throws on a mismatch.
  return a.length === b.length && timingSafeEqual(a, b);
}

Verify against the raw request body, before any JSON parsing re-serialises it.

Acknowledging and retries

  • Answer with any 2xx within 8 seconds to acknowledge.

  • Anything else is retried, eight attempts in all, spaced out over roughly two hours (10 s, 30 s, 2 min, 5 min, 15 min, 30 min, 1 h).

  • After 50 consecutive failed deliveries the webhook is paused. Saving the URL again in Developer turns it back on.

  • Send test in Developer delivers a signed sample, so you can check your receiver before a real code depends on it.

Rotating the secret

Rotate secret issues a new one immediately. Update your receiver straight after: deliveries from then on are signed with the new secret.

Updated