Webhooks
eSimerge POSTs a signed payload to your endpoint whenever something relevant happens — no polling required.
Register an endpoint
From the partner portal → Developers → Webhooks tab → New endpoint. Enter a public HTTPS URL that accepts POST. The signing secret is shown once — store it.
Available events
| Event | Description |
|---|---|
order.issued | Order accepted and eSIM provisioned successfully. |
order.failed | Provisioning failed (insufficient balance, plan unavailable, etc.). |
esim.activated | Customer installed and activated the eSIM on their device. |
esim.expired | Plan validity has elapsed. |
esim.usage.threshold | Usage crossed 50% / 80% / 100% of the plan's data. |
order.topup.completed | A top-up (extra data / extra days) was successfully applied to an existing eSIM. |
order.topup.failed | A top-up could not be applied. Payload includes code and reason. |
Request shape
Every delivery includes:
POST /your/webhook/url
X-eSimerge-Signature: t=1748275200,v1=<hex_hmac_sha256>
X-eSimerge-Event: esim.activated
X-eSimerge-Delivery: dlv_AbCdEf...
Content-Type: application/json
{
"id": "evt_AbCdEf...",
"type": "esim.activated",
"created_at": "2026-05-26T12:00:00Z",
"data": {
"esim_id": "esm_esim_...",
"order_id": "esm_order_...",
"iccid": "8988..."
}
}Verify the signature
Rebuild the string `${t}.${rawBody}`, compute HMAC-SHA256 with the signing secret, and compare it to v1 using a timing-safe compare. Reject the request if t is older than 5 minutes (replay protection).
import { createHmac, timingSafeEqual } from "crypto";
export function verifyeSimergeSignature(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const ts = parts.t;
if (!ts || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${ts}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 || "");
return a.length === b.length && timingSafeEqual(a, b);
}Retries
A delivery is considered successful when your endpoint returns 2xx within 60 seconds. On failure we retry the same delivery on this schedule:
- +30 seconds
- +60 seconds
- +3 minutes
- +5 minutes
- +15 minutes
If the delivery still fails after those 5 retries, the endpoint is blocked for 1 minute — no new deliveries are sent during the block. After 5 consecutive blocks the endpoint is fully disabled and must be re-enabled from the API page in the partner dashboard (use the status switch on the endpoint row). Every attempt is recorded in the Delivery log with status code and latency.
Security tips
- Always verify the signature — never trust
X-eSimerge-Eventalone. - Return
200immediately and process in the background — don't slow down delivery. - Use the event
idas an idempotency key to ignore duplicate deliveries. - Log
X-eSimerge-Deliveryto attach when contacting support.