Skip to content

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.

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.

{
"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.

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 with any 2xx status 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.