Webhooks
Add a webhook endpoint in the panel and choose which events it receives. Roamex then sends each event to your URL as a POST with a JSON body.
Events
Section titled “Events”| Type | When |
|---|---|
order.created |
An order was placed. |
esim.provisioned |
The eSIMs of an order were created. Their QR code can follow a little later. |
esim.activated |
An eSIM connected to a network for the first time. |
esim.topped_up |
An eSIM was topped up. |
esim.low_data |
An eSIM is running low on data. |
esim.expiring_soon |
An eSIM expires soon. |
customer_topup.succeeded |
A traveller paid for a top-up. |
wallet.topped_up |
Money was added to your wallet. |
wallet.low_balance |
Your wallet balance is low. |
You can also read the newest events with Recent events.
The request
Section titled “The request”{ "id": "delivery id", "event_id": "event id", "type": "esim.topped_up", "created_at": "2026-10-22T09:30:00.000Z", "sent_at": "2026-10-22T09:30:01.000Z", "data": { }}Headers:
| Header | Value |
|---|---|
X-Roamex-Event |
The event type. |
X-Roamex-Delivery |
The delivery id. Stays the same on a retry. |
X-Roamex-Event-Id |
The event id. |
X-Roamex-Signature |
sha256= followed by the HMAC-SHA256 of the raw body, hex, made with your endpoint secret. |
Check the signature
Section titled “Check the signature”Compute the HMAC over the raw body, before you parse it:
import { createHmac, timingSafeEqual } from 'node:crypto'
function isFromRoamex(rawBody, signatureHeader, secret) { const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex') const a = Buffer.from(expected) const b = Buffer.from(signatureHeader ?? '') return a.length === b.length && timingSafeEqual(a, b)}Answer and retries
Section titled “Answer and retries”- Answer with any
2xxstatus within 10 seconds. - Otherwise we try again, up to 6 attempts in total, after 1, 5, 15, 60 and 360 minutes.
- Redirects are not followed.

