Getting started

First sandbox order

Five calls take you from an API key to an installable eSIM. Everything below runs against the sandbox and costs nothing.

What you need

A sandbox key from the portal (see Get your API keys) and a terminal with curl and jq. Your sandbox balance is pre-loaded with play money.

0. Set your key

bash
export JS_KEY="js_test_your_sandbox_key_here"

1. Confirm the key

bash
curl -s https://app.journeystack.co/api/public/v1/ping -H "Authorization: Bearer $JS_KEY" | jq
200 OK
{
  "data": {
    "ok": true,
    "environment": "sandbox",
    "partner": "Acme Travel",
    "currency": "USD",
    "server_time": "2026-01-14T09:30:00.000Z"
  }
}

2. Find a plan and capture its ID

Plan IDs are account-independent but they are not fixed forever — always read them from the catalogue rather than hard-coding one. This call stores the cheapest unlimited Singapore plan in a shell variable.

bash
PLAN_ID=$(curl -s "https://app.journeystack.co/api/public/v1/plans?country=SG&type=unlimited&limit=1" \
  -H "Authorization: Bearer $JS_KEY" | jq -r '.data[0].id')

echo "$PLAN_ID"
# 0f4c1c2e-6f8a-4a09-9f0d-2f1b8c7d5e41

Check `validity.billed_per_day` on the plan. When it is true the plan is sold per day and you must send `days` on the order; when it is false the plan has fixed validity and `days` is ignored.

3. Order the eSIM

The `Idempotency-Key` should be something stable from your own system — a booking reference works well. If the call times out you resend the identical request and get the original order back instead of a second purchase.

bash
ORDER=$(curl -s -X POST https://app.journeystack.co/api/public/v1/orders \
  -H "Authorization: Bearer $JS_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: BK-90210" \
  -d "{
    \"plan_id\": \"$PLAN_ID\",
    \"quantity\": 1,
    \"days\": 7,
    \"customer\": { \"name\": \"Ada Lovelace\", \"email\": \"ada@example.com\", \"reference\": \"BK-90210\" }
  }")

echo "$ORDER" | jq '.data.status, .data.price, .data.esims[0].id'
201 Created (extract)
"completed"
{ "unit": 17.15, "total": 17.15, "currency": "USD" }
"9ac2d51b-8f2e-4d6e-b0a1-6c5f0d9a3b77"

4. Deliver the eSIM

The order response already contains everything the traveller needs. You can also fetch it again at any time, which is what you do when someone asks you to resend the QR code.

bash
ESIM_ID=$(echo "$ORDER" | jq -r '.data.esims[0].id')

curl -s https://app.journeystack.co/api/public/v1/esims/$ESIM_ID \
  -H "Authorization: Bearer $JS_KEY" | jq '{ qr_code_url, activation_code, smdp_address, status }'
200 OK
{
  "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"
}

Sandbox QR codes do not provide connectivity

A sandbox profile is a realistic, correctly formatted record with a scannable QR image, but it is not a real eSIM. Installing it on a phone will not connect to a network, and it will never report usage on its own. Use it to build and test your delivery flow, then repeat the same calls with a live key.

5. Check usage and balance

bash
curl -s https://app.journeystack.co/api/public/v1/esims/$ESIM_ID/usage -H "Authorization: Bearer $JS_KEY" | jq
curl -s https://app.journeystack.co/api/public/v1/wallet -H "Authorization: Bearer $JS_KEY" | jq

Next

Run the same calls interactively in the sandbox console, then read Purchase and deliver an eSIM for the production-grade version of step 3.