Build travel eSIMs into your product
Sell eSIMs from your own app or website with one REST API. Search the catalogue, place orders and deliver installable eSIMs to your customers, under your brand.
The whole eSIM lifecycle, inside your own product
From choosing a plan to topping up mid-trip, each step your customer takes is an API call you control.
Sell any plan in your catalogue
Filter plans by country, region, data and duration, then place an order for a customer with one call. Every plan comes back with the price you pay for it.
- Filter by country, region, data and days
- Orders are paid from your prepaid credit
- Idempotency keys make retries safe
Deliver the eSIM in your own flow
When an order is fulfilled you get the ICCID, the LPA activation string and a QR code, by webhook or by reading the order.
- order.fulfilled webhook, signed
- QR code as a PNG, ready to show or email
- LPA string for one-tap installs in your app
Keep travellers connected after the sale
Offer data top-ups, move an eSIM to a new phone, refund eligible orders and download invoices, all from the same API.
- Top-ups priced for your account
- Reinstall an eSIM on a new device
- Refunds and PDF invoices per order
Everything you need to ship with confidence
Free sandbox
Test keys run the whole flow, from order to eSIM to webhook, without calling a network or spending credit.
Signed requests
Every request is signed with HMAC-SHA256 and a timestamp, and replays are rejected. Keys can be limited to your servers' IP addresses.
Webhooks that retry
Signed events for orders, eSIMs, top-ups and credit, retried with backoff for more than a day, with a delivery log you can replay.
Safe to retry
Send an Idempotency-Key with orders and top-ups. A repeat within 24 hours returns the first response instead of charging twice.
OpenAPI 3.1 spec
Import the spec into Postman or generate a typed client, or start from the curl, Node and Python samples in the docs.
Scoped keys, clear limits
Give each key read, order or full access. Rate limits are per key, and every authenticated response shows what is left.
Explore the docs
Every endpoint has a request and a response you can copy. Sign with your key, point at the sandbox and start.
curl --request GET \
--url 'https://api.roamgo.net/api/partner/v1/plans?country=JP&minDays=7' \
--header 'Authorization: Roamgo-HMAC-SHA256 keyId=<KEY_ID>, ts=<UNIX>, sig=<SIGNATURE>'{
"plans": [{
"id": "cm...",
"name": "Japan 10 GB",
"countries": ["JP"],
"dataAmountMB": 10240,
"validityDays": 30,
"yourPriceCents": 1840,
"currency": "USD"
}],
"page": 1,
"pageSize": 24,
"total": 18
}curl --request POST \
--url 'https://api.roamgo.net/api/partner/v1/orders' \
--header 'Authorization: Roamgo-HMAC-SHA256 keyId=<KEY_ID>, ts=<UNIX>, sig=<SIGNATURE>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <UNIQUE_KEY>' \
--data '{"planId":"cm_plan_id","quantity":1,"customerEmail":"traveler@example.com","externalRef":"BOOKING-49102"}'HTTP/1.1 202 Accepted
{
"order": {
"id": "cm_order_id",
"status": "PAID",
"customerEmail": "traveler@example.com",
"totalCents": 1840,
"currency": "USD"
}
}curl --request GET \
--url 'https://api.roamgo.net/api/partner/v1/esims/cm_esim_id/qr' \
--header 'Authorization: Roamgo-HMAC-SHA256 keyId=<KEY_ID>, ts=<UNIX>, sig=<SIGNATURE>' \
--output esim-qr.pngHTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: private, max-age=3600curl --request POST \
--url 'https://api.roamgo.net/api/partner/v1/esims/cm_esim_id/topups' \
--header 'Authorization: Roamgo-HMAC-SHA256 keyId=<KEY_ID>, ts=<UNIX>, sig=<SIGNATURE>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <UNIQUE_KEY>' \
--data '{"topUpProviderPlanId":"topup_1gb_7d","externalRef":"BOOKING-49102-TOPUP-1"}'HTTP/1.1 201 Created
{
"topUp": {
"id": "cm_topup_id",
"status": "COMPLETED",
"priceCents": 480,
"currency": "USD"
}
}import crypto from "node:crypto";
// X-Roamgo-Signature: t=<unix>,v1=<hex>
export function verifyRoamgoSignature(rawBody: string, header: string, secret: string) {
const match = header.match(/^t=(\d+),v1=([0-9a-f]+)$/);
if (!match) return false;
const [, ts, v1] = match;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(v1, "hex"));
}{
"id": "evt_8d…",
"type": "order.fulfilled",
"createdAt": "2026-09-30T09:14:02.118Z",
"livemode": true,
"data": {
"order": {
"id": "cm_order_id",
"status": "FULFILLED",
"items": [{
"esims": [{
"iccid": "8910…",
"lpaString": "LPA:1$...",
"status": "ISSUED"
}]
}]
}
}
}One API for every part of the sale
Each resource links to its reference, with parameters, errors and examples.
Catalog
Orders
eSIMs
Account
Integrate the API, or launch without code
The API is one way to sell. The options below run on the same catalogue, credit and fulfilment.
Start building in the sandbox
Create a free partner account, generate test keys in the dashboard and run a full order, QR code and webhooks included, before you add any credit.