- Home
- Blog
- API & Integration
- eSIM Webhooks: Automating Order Status, Activation and Expiry
eSIM Webhooks: Automating Order Status, Activation and Expiry
eSIM webhooks are HTTP callbacks that tell your system when something changes — an order completes, fails or is refunded, or an eSIM is activated or expires — so you don't have to poll the API. On Fully Signal each webhook is signed with HMAC-SHA256 in the X-FULLYSIGNAL-Signature header and retried automatically if your endpoint is down.
In this article
Polling an API every few minutes to see whether anything changed is slow, wasteful and easy to get wrong. Webhooks flip it around: the platform calls you the moment something happens.
The events
On Fully Signal, partners can receive these events:
| Event | When it fires | What you might do |
|---|---|---|
order.completed | An order has its eSIM ready | Email the install link, mark the booking paid |
order.failed | An order could not be fulfilled | Alert support, offer an alternative plan |
order.refunded | An order was refunded | Update your accounting, notify the customer |
esim.activated | The eSIM was installed / started | Send a "you're connected" message with tips |
esim.expired | The plan ended | Ask for a review, offer a plan for the next trip |
The payload
Each webhook is a JSON POST:
{
"event": "esim.activated",
"created": 1767200000,
"data": { "order_id": "BO-7F3K2", ... }
}
Every event carries an order_id, so one handler can find the booking whatever the event.
Verifying the signature
Never trust a webhook just because it reached your URL. Fully Signal signs every delivery Stripe-style in the X-FULLYSIGNAL-Signature header:
X-FULLYSIGNAL-Signature: t=1767200000,v1=5f2c…
Compute HMAC-SHA256 of "<t>.<raw body>" with your webhook secret and compare it with v1. In Node.js:
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const expected = crypto.createHmac('sha256', secret)
.update(parts.t + '.' + rawBody).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(parts.v1 || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Use the raw request body, not a re-serialised JSON object, and reject timestamps that are too old to block replays.
Retries and reliability
If your endpoint is down or returns an error, the delivery is retried automatically (up to six attempts). The partner panel's webhook log shows every delivery, its response and its status, so you can debug without guessing.
Best practices:
- Respond 2xx fast — do the heavy work in a background job
- Be idempotent — the same event may arrive twice; deduplicate on event and order
- Don't depend on order — handle
esim.activatedeven if you missedorder.completed - Log everything — store the raw payload for support and audits
Ideas that drive revenue
- On
esim.activated: send a welcome message with a top-up link — customers who run low buy from you (top-ups) - On
esim.expired: ask for a review and offer a discount for the next trip - On
order.failed: switch automatically to a similar package and notify the customer
FAQ
What is an eSIM webhook?
An HTTP request the eSIM platform sends to your server when an order or eSIM changes state, so your system can react instantly.
How do I secure webhooks?
Verify the HMAC-SHA256 signature on every request with your webhook secret, use HTTPS, and reject stale timestamps.
What happens if my server is down?
Fully Signal retries the delivery automatically, and the webhook log shows every attempt.
Can I test webhooks without real orders?
Yes. The partner panel can send a signed test webhook to your URL. Sandbox orders themselves never send webhooks or customer emails, so test those flows with the test event. See sandbox testing.