STMobile

Wholesale eSIM API

One integration, several carriers. You keep the customer; we provision the line. Base URL https://solutiontelecommobile.com/v1OpenAPI 3.0.

Start in sandbox. A key that begins with stm_sandbox_ walks the exact same code path — same validation, same idempotency, same response shape — but it never contacts a carrier and never touches your balance. Integrate with it while your account is being onboarded.

Authentication

curl https://solutiontelecommobile.com/v1/balance \
  -H "Authorization: Bearer stm_sandbox_your_key_here"

Buying — and the one header that matters

curl -X POST https://solutiontelecommobile.com/v1/orders \
  -H "Authorization: Bearer $STM_KEY" \
  -H "Idempotency-Key: your-order-4711" \
  -H "Content-Type: application/json" \
  -d '{"sku":"PFRQ8FIBC","quantity":1,"reference":"your-order-4711"}'
eSIM purchases cannot be refunded. If your request times out and you retry without the same Idempotency-Key, you buy twice and pay twice. Send the key, reuse it on every retry, and we return the original response — same body, same status. Reusing a key with a different body returns 409, because that means you meant a different purchase.

Endpoints

MethodPathWhat it does
GET /v1/catalogPlans available to you, already at your price
GET /v1/catalog/{sku}A single plan
POST /v1/ordersBuy — requires Idempotency-Key
GET /v1/ordersYour orders, newest first
GET /v1/orders/{id}One order, with ICCID, LPA and QR payload
POST /v1/orders/{id}/topupAdd data to an eSIM already sold — the QR does not change
GET /v1/balancePrepaid balance
GET /v1/usage/{iccid}Data used, remaining and expiry for one eSIM

What an order looks like

{
  "data": {
    "id": 5,
    "environment": "sandbox",
    "status": "delivered",
    "sku": "PFRQ8FIBC",
    "quantity": 1,
    "unit_price_usd": "0.3750",
    "total_price_usd": "0.3750",
    "currency": "USD",
    "reference": null,
    "topup_of": 4,
    "esims": [{
      "iccid": "8955...",
      "activation_code": "LPA:1$smdp.example$MATCHINGID",
      "qrcode": "LPA:1$smdp.example$MATCHINGID"
    }]
  }
}

Top-ups keep the QR. POST /v1/orders/{id}/topup returns a new order with topup_of pointing at the original — the traveller installs nothing again, the data simply lands on the same eSIM.

Limits

Two of them, and the second is the one that protects you: a cap on requests per minute, and a cap on how much balance can be spent per hour. A loop without a sleep can otherwise drain your account in seconds. When you hit either, we answer 429 with Retry-After — retry with the same key, never a new one.

Errors

StatusCodeMeaning
400missing_idempotency_keyThe buying endpoints require it
401invalid_tokenKey is wrong or revoked
402insufficient_balanceTop up your account
403account_not_liveOnboarding not finished — use a sandbox key
404not_foundPlan or order not available to your account
409idempotency_key_reuseSame key, different body
429rate_limitToo many requests, or hourly spend cap
502carrier_errorCarrier failed — your balance was returned automatically

Versioning, in one sentence

We add fields freely; we never rename or remove one without publishing /v2 and keeping /v1 running. Write your parser to ignore unknown fields and your integration will not break.

Talk to us about getting a key