API reference
Create an order
Buys one or more eSIMs, debits your prepaid balance and returns the installable eSIM.
POST
https://app.journeystack.co/api/public/v1/ordersBody parameters
| Field | Type | Description |
|---|---|---|
plan_idrequired | uuid | A plan ID from GET /plans. |
quantity | integerdefault 1 | How many eSIMs to issue, 1–50. Each is a separate profile. |
days | integer | Number of days for per-day (unlimited) plans, 1–365. Rejected on fixed plans with any value other than 1. |
customer.name | string | Traveller name, up to 120 characters. Stored for your reporting only. |
customer.email | string | Traveller email, valid address up to 255 characters. |
customer.reference | string | Your own booking reference, up to 120 characters. |
Behaviour you should rely on
- Always send an
Idempotency-Keyheader. Replays return the original order withIdempotent-Replay: trueand never charge twice. - Returns HTTP 201 on a new order and HTTP 200 on an idempotent replay.
- If issuing fails the call returns
provider_errorand your balance is refunded automatically in the same request.
Request
cURL
curl -X POST https://app.journeystack.co/api/public/v1/orders \
-H "Authorization: Bearer $JS_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: booking-90210" \
-d '{
"plan_id": "0f4c1c2e-6f8a-4a09-9f0d-2f1b8c7d5e41",
"quantity": 1,
"days": 7,
"customer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"reference": "BK-90210"
}
}'body
{
"plan_id": "0f4c1c2e-6f8a-4a09-9f0d-2f1b8c7d5e41",
"quantity": 1,
"days": 7,
"customer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"reference": "BK-90210"
}
}Response
201 Created
{ "data": {
"id": "b1f0a3c9-70d2-4b55-9a3f-4f2e1c8d9a10",
"status": "completed",
"environment": "sandbox",
"plan_id": "0f4c1c2e-6f8a-4a09-9f0d-2f1b8c7d5e41",
"quantity": 1,
"days": 7,
"price": { "unit": 17.15, "total": 17.15, "currency": "USD" },
"customer": { "name": "Ada Lovelace", "email": "ada@example.com", "reference": "BK-90210" },
"error": null,
"created_at": "2026-01-14T09:31:01.880Z",
"esims": [{
"id": "9ac2d51b-8f2e-4d6e-b0a1-6c5f0d9a3b77",
"plan_name": "Singapore Unlimited",
"iccid": "8944478000123456789",
"qr_code_url": "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=LPA%3A1%24sandbox.journeystack.co%24A1B2C3D4E5",
"activation_code": "LPA:1$sandbox.journeystack.co$A1B2C3D4E5",
"smdp_address": "sandbox.journeystack.co",
"status": "ALLOCATED",
"validity_days": 7,
"data": { "unlimited": true, "total_bytes": null, "used_bytes": 0 },
"install": { "instructions": "On the device go to Settings > Cellular / Mobile Data > Add eSIM, then scan the QR code or enter the activation code manually." },
"created_at": "2026-01-14T09:31:02.114Z"
}]
} }Selected response fields
| Field | Type | Description |
|---|---|---|
status | string | completed when eSIMs were issued. failed orders are refunded in full. |
price.unit | number | Price of one eSIM, already multiplied by days on per-day plans. |
price.total | number | Amount debited from your balance. |
esims | array | One object per eSIM, with QR code and activation code ready to deliver. |
Errors
| Code | HTTP | What to do |
|---|---|---|
| unauthorized | 401 | Check the Authorization header and that the key is still active in your portal. |
| invalid_request | 400 | Read `error.details` for the offending field, fix and resend. |
| insufficient_funds | 402 | Top up, then retry with the same idempotency key. |
| not_found | 404 | Re-fetch the ID. Plans return not_found once they are retired from the catalogue. |
| rate_limited | 429 | Honour `Retry-After` (60 seconds) and back off. Ask support for a higher limit. |
| provider_error | 502 | You were refunded in full. Safe to place a new order with a new idempotency key. |
| internal_error | 500 | Retry with the same idempotency key — it can never double-charge you. |
Sandbox console
Run this endpoint against the sandbox with your own test key. Nothing is provisioned on the live network and no real money moves.