partner api

Sell global eSIM data under your own brand. You call goAFK, we handle the carrier relationship, and your end users never see a third party.

Base URLhttps://goafk.io/api/v1

quickstart

Partner accounts are opened by our team — there is no self-serve signup. Once your account exists you will have an API key and a pre-paid USD balance. Three calls take you from nothing to a working eSIM.

1. Find a plan. 2. Buy it. 3. Give the returned activation code to your end user. That is the whole integration.

1 · find a plan
curl https://goafk.io/api/v1/plans?country=FR \
  -H "Authorization: Bearer $GOAFK_API_KEY"
2 · buy it
curl -X POST https://goafk.io/api/v1/esims \
  -H "Authorization: Bearer $GOAFK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":"156057"}'

The response carries esim.activation_code — an LPA string. Show it to your user as text or as a QR code and the profile installs. Nothing else is required.

authentication

Every request carries your API key as a bearer token. Keys look like gak_live_… and are shown exactly once, at the moment we create them: we store only a hash, so a lost key cannot be recovered and has to be replaced.

Authorization: Bearer gak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Treat the key like a password. It authorises spending against your balance, so it belongs on your server only — never in a browser, a mobile app, or a public repository. If a key is exposed, tell us and we will revoke it; revocation takes effect on the next request.

A missing, malformed, unknown or revoked key all return the same 401 INVALID_API_KEY. That is deliberate — the error never confirms that a particular key once existed.

balance & pricing

Your account holds a pre-paid balance in USD. Buying an eSIM or a top-up debits it; nothing else does. Every amount in this API is an integer number of cents — there are no floating-point prices to round.

Prices are personal to your account: the catalogue is returned at wholesale plus your contracted markup, so price_usd_cents from GET /plans is exactly what you will be charged. Two partners can see different numbers for the same plan, and that is expected.

The debit is atomic and happens before we ask the carrier for an eSIM. If your balance will not cover the plan you get 402 INSUFFICIENT_FUNDS and nothing is charged. If the debit succeeds but the carrier then refuses, we write a compensating refund automatically and mark the order provider_failed — you are never charged for an eSIM you did not receive.

To add funds, contact your account manager. Top-ups are not yet self-serve.

idempotency

Both spending endpoints — POST /esims and POST /esims/{id}/topup — require an Idempotency-Key header. It is not optional, because a network timeout on a purchase is otherwise indistinguishable from a failure, and retrying blind would charge you twice.

Use any string up to 200 characters; a fresh UUID per logical purchase is the usual choice. Store it before you send the request, so a retry after a crash can reuse it.

Replaying a key returns the original order with Idempotency-Replayed: true and does not charge again. The key is the unit of replay, not the request body: sending a different plan_id under a key you already used returns the first order, it does not buy the second plan. Always use a new key for a genuinely new purchase.

rate limits

Each API key has a requests-per-minute ceiling agreed with your account manager. Every authenticated response reports where you stand:

HeaderMeaning
X-RateLimit-LimitYour ceiling, in requests per minute.
X-RateLimit-RemainingRequests left in the current 60-second window.
Retry-AfterSeconds to wait. Sent only with a 429.
X-Request-IdOn every response. Quote it in a support ticket and we can find the exact request.

Over the limit you get 429 RATE_LIMITED. Back off for the Retry-After interval rather than retrying immediately. GET /plans is the call most worth caching: the catalogue changes slowly and it is not paginated.

errors

Every failure returns the same shape, with the HTTP status carrying the category and error.code carrying the specific reason. Branch on the code — the message is written for humans and its wording can change.

Error body
{
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Partner balance is insufficient for plan price 4.50 USD",
    "request_id": "6f1d0b3e-6c1a-4a4e-9f2a-1c2d3e4f5a6b"
  }
}
StatusCodeWhat it meansWhat to do
400INVALID_REQUESTA required field is missing or the wrong type.Fix the request. Retrying it unchanged will fail the same way.
400IDEMPOTENCY_KEY_REQUIREDA spending operation arrived without an Idempotency-Key header.Send one. It is required so a retry cannot double-charge you.
400IDEMPOTENCY_KEY_TOO_LONGThe Idempotency-Key exceeded 200 characters.Use a shorter key — a UUID is ideal.
401INVALID_API_KEYThe key is missing, malformed, unknown, or revoked.Check the Authorization header format. An unknown key and a revoked key are reported identically on purpose, so this error never confirms a key once existed.
402INSUFFICIENT_FUNDSThe purchase price exceeds your balance. NOTHING was charged.Top up your balance with your account manager, then retry.
403PARTNER_SUSPENDEDYour account is suspended. Reads and writes are both refused.Contact your account manager. Retrying will not help.
404PLAN_NOT_FOUNDNo plan with that id.Re-fetch the catalogue; plan ids change as the carrier catalogue changes.
404ESIM_NOT_FOUNDNo eSIM with that id in YOUR account.Check the id. An eSIM belonging to another partner returns this same 404, so it is never possible to probe for one.
404ORDER_NOT_FOUNDNo order with that id in your account.Check the id.
405METHOD_NOT_ALLOWEDThe HTTP verb is not supported on that path.Check the reference below for the verb each path accepts.
429RATE_LIMITEDYou exceeded your requests-per-minute ceiling.Back off for the Retry-After interval, then retry.
500INTERNAL_ERRORSomething failed on our side.Retry with the SAME Idempotency-Key if the call spends money. Quote the request_id if it persists.
502PROVIDER_ERRORThe carrier refused or could not be reached.For a purchase or top-up your balance has ALREADY been refunded automatically — retry with a NEW Idempotency-Key to try again.

webhooks

Rather than polling, you can have us POST to your server when something happens on your account. Add an endpoint in the partner dashboard, where you will also find its signing secret and a log of recent deliveries.

Every delivery is a JSON body with the same envelope. Deduplicate on id: a retry re-sends the identical body, so a receiver that has already processed an id should acknowledge and do nothing.

Delivery body
{
  "id": "whd_7c1e2f30-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "event": "esim.purchased",
  "created_at": "2026-08-17T09:24:11.482Z",
  "data": {
    "esim": {
      "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "iccid": "8944478000001234567",
      "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
      "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
      "status": "inactive",
      "data_total_mb": 5120,
      "data_used_mb": 0,
      "expires_at": null,
      "plan_id": "156057"
    },
    "order": {
      "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
      "kind": "purchase",
      "price_usd_cents": 1595,
      "currency": "USD",
      "plan_id": "156057",
      "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "status": "completed",
      "created_at": "2026-08-17T09:24:11.482Z"
    }
  }
}

Verifying the signature

Anyone can POST to your endpoint. The signature is what proves a delivery came from us — check it before acting on the body, and compare in constant time.

HeaderMeaning
X-goAFK-Signaturet=<unix seconds>,v1=<hex> — HMAC-SHA256 of `${t}.${rawBody}` using your endpoint secret.
X-goAFK-EventThe event name, so you can route without parsing the body.
X-goAFK-DeliveryThe delivery id, identical to id in the body.

Sign the raw request body, not a re-serialized object — re-encoding changes the bytes and the signature will not match. Reject anything whose timestamp is more than 5 minutes from your own clock, which is what stops a captured delivery being replayed later.

Node.js
const crypto = require('crypto');

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(',').map(p => p.trim().split('=')),
  );
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t));
  if (!Number.isFinite(age) || age > 300) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');

  // Constant time: a plain === leaks the answer one byte at a time.
  return parts.v1.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}

Retries

Reply with any 2xx and we stop. Reply with a 5xx, a 408, a 429, or nothing at all, and we retry 6 times with increasing gaps — 1m, 5m, 30m, 2h, 6h, 24h — which spans more than a day in total.

Any other 4xx stops the retries immediately. A 404 or a 401 means the endpoint is misconfigured, and the same request would fail identically six hours later. Acknowledge first and process afterwards: we time out after 10 seconds, and a slow reply costs you a duplicate delivery.

Events

esim.purchased

A POST /esims succeeded and an eSIM was issued.

{
  "id": "whd_7c1e2f30-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "event": "esim.purchased",
  "created_at": "2026-08-17T09:24:11.482Z",
  "data": {
    "esim": {
      "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "iccid": "8944478000001234567",
      "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
      "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
      "status": "inactive",
      "data_total_mb": 5120,
      "data_used_mb": 0,
      "expires_at": null,
      "plan_id": "156057"
    },
    "order": {
      "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
      "kind": "purchase",
      "price_usd_cents": 1595,
      "currency": "USD",
      "plan_id": "156057",
      "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "status": "completed",
      "created_at": "2026-08-17T09:24:11.482Z"
    }
  }
}

esim.topped_up

A top-up succeeded and the eSIM has more data.

{
  "id": "whd_7c1e2f30-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "event": "esim.topped_up",
  "created_at": "2026-08-17T09:24:11.482Z",
  "data": {
    "esim": {
      "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "iccid": "8944478000001234567",
      "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
      "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
      "status": "inactive",
      "data_total_mb": 5120,
      "data_used_mb": 0,
      "expires_at": null,
      "plan_id": "156057"
    },
    "order": {
      "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
      "kind": "purchase",
      "price_usd_cents": 1595,
      "currency": "USD",
      "plan_id": "156057",
      "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "status": "completed",
      "created_at": "2026-08-17T09:24:11.482Z"
    }
  }
}

order.failed

We charged you, the carrier refused, and the money was returned automatically.

{
  "id": "whd_7c1e2f30-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "event": "order.failed",
  "created_at": "2026-08-17T09:24:11.482Z",
  "data": {
    "order_id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
    "error_code": "PROVIDER_ERROR",
    "refunded_cents": 1595,
    "currency": "USD"
  }
}

balance.low

A purchase took your balance below your alert threshold. Fires on the crossing only.

{
  "id": "whd_7c1e2f30-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "event": "balance.low",
  "created_at": "2026-08-17T09:24:11.482Z",
  "data": {
    "balance_cents": 640,
    "threshold_cents": 1000,
    "currency": "USD"
  }
}

plans

Browse the catalogue at your own pricing.

GET/plans

List available plans

Returns the full catalogue, priced at your markup. This endpoint is NOT paginated — narrow it with the filters below rather than fetching everything on each page load, and cache the result.

Parameters

NameInTypeDescription
countryquerystringISO 3166-1 alpha-2 country code. Case-insensitive.
regionquerystringRegional grouping, matched exactly and case-sensitively.
Request
curl -X GET https://goafk.io/api/v1/plans \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "plans": [
    {
      "id": "156057",
      "country_code": "FR",
      "country_name": "France",
      "region": "Europe",
      "type": "fixed",
      "data_gb": 5,
      "duration_days": 30,
      "price_usd_cents": 1595,
      "currency": "USD"
    }
  ]
}

Responses

StatusMeaning
200The catalogue.
401Missing, malformed, unknown or revoked API key.
429Rate limit exceeded. Retry after the Retry-After interval.

GET/plans/{id}

Retrieve one plan

Fetch a single plan by id, priced at your markup.

Parameters

NameInTypeDescription
idrequiredpathstringThe plan id.
Request
curl -X GET https://goafk.io/api/v1/plans/156057 \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "plan": {
    "id": "156057",
    "country_code": "FR",
    "country_name": "France",
    "region": "Europe",
    "type": "fixed",
    "data_gb": 5,
    "duration_days": 30,
    "price_usd_cents": 1595,
    "currency": "USD"
  }
}

Responses

StatusMeaning
200The plan.
401Missing, malformed, unknown or revoked API key.
404No plan with that id.

esims

Issue eSIMs, inspect them, and top them up.

POST/esims

Buy an eSIM

Debits your balance and issues an eSIM. The debit happens FIRST and is atomic: if it fails, nothing else runs. If the debit succeeds but the carrier then refuses, the charge is automatically reversed and the order is recorded as `provider_failed` — you are never charged for an eSIM you did not receive.

An `Idempotency-Key` header is REQUIRED. If a request times out, retry it with the SAME key: the reply is the original order, and no second charge is made.

Parameters

NameInTypeDescription
Idempotency-KeyrequiredheaderstringREQUIRED on every operation that spends money. Any string up to 200 characters; a UUID per logical purchase is the usual choice. Replaying a key returns the original order instead of charging again.

Request body

FieldTypeDescription
plan_idstringThe id of the plan to buy, from GET /plans.
Request
curl -X POST https://goafk.io/api/v1/esims \
  -H "Authorization: Bearer $GOAFK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":"156057"}'
Response · 201
{
  "esim": {
    "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "iccid": "8944478000001234567",
    "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
    "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
    "status": "inactive",
    "data_total_mb": 5120,
    "data_used_mb": 0,
    "expires_at": null,
    "plan_id": "156057"
  },
  "order": {
    "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
    "kind": "purchase",
    "price_usd_cents": 1595,
    "currency": "USD",
    "plan_id": "156057",
    "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "status": "completed",
    "created_at": "2026-08-17T09:24:11.482Z"
  }
}

Responses

StatusMeaning
201The eSIM was issued and your balance was debited. On an idempotent replay the status is still 201, with `Idempotency-Replayed: true` set.
400plan_id is missing, or the Idempotency-Key header is absent or over 200 characters.
401Missing, malformed, unknown or revoked API key.
402Your balance will not cover this plan. Nothing was charged.
404No plan with that id.
502The carrier refused. Your balance has already been refunded.

GET/esims

List your eSIMs

Your own eSIMs only, newest first. Another partner's inventory is never visible.

Parameters

NameInTypeDescription
pagequeryinteger1-based page number. Values below 1 are clamped to 1.
limitqueryintegerRows per page. Clamped to the 1–100 range.
Request
curl -X GET https://goafk.io/api/v1/esims \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "esims": [
    {
      "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "iccid": "8944478000001234567",
      "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
      "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
      "status": "inactive",
      "data_total_mb": 5120,
      "data_used_mb": 0,
      "expires_at": null,
      "plan_id": "156057"
    }
  ],
  "total": 128,
  "page": 1,
  "limit": 50
}

Responses

StatusMeaning
200A page of eSIMs.
401Missing, malformed, unknown or revoked API key.

GET/esims/{id}

Retrieve one eSIM

Returns cached fields, which is enough to render an installation screen. For live consumption use the usage endpoint instead.

Parameters

NameInTypeDescription
idrequiredpathstringThe goAFK eSIM id (not the ICCID).
Request
curl -X GET https://goafk.io/api/v1/esims/9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6 \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "esim": {
    "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "iccid": "8944478000001234567",
    "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
    "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
    "status": "inactive",
    "data_total_mb": 5120,
    "data_used_mb": 0,
    "expires_at": null,
    "plan_id": "156057"
  }
}

Responses

StatusMeaning
200The eSIM.
401Missing, malformed, unknown or revoked API key.
404No such eSIM in YOUR account. An id belonging to another partner also returns 404.

POST/esims/{id}/topup

Top up an eSIM

Adds another plan to an eSIM you already issued, keeping the same ICCID so the end user does not reinstall anything. Charging works exactly as it does for a purchase: atomic debit first, automatic refund if the carrier refuses, and an `Idempotency-Key` header is REQUIRED.

Parameters

NameInTypeDescription
idrequiredpathstringThe goAFK eSIM id to top up.
Idempotency-KeyrequiredheaderstringREQUIRED on every operation that spends money. Any string up to 200 characters; a UUID per logical purchase is the usual choice. Replaying a key returns the original order instead of charging again.

Request body

FieldTypeDescription
plan_idstringThe plan to add.
Request
curl -X POST https://goafk.io/api/v1/esims/9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6/topup \
  -H "Authorization: Bearer $GOAFK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":"156057"}'
Response · 201
{
  "esim": {
    "id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "iccid": "8944478000001234567",
    "activation_code": "LPA:1$smdp.example.com$QR-G-5C-1LO-1S9L3JT",
    "qr_code_url": "https://cdn.example.com/qr/8944478000001234567.png",
    "status": "inactive",
    "data_total_mb": 5120,
    "data_used_mb": 0,
    "expires_at": null,
    "plan_id": "156057"
  },
  "order": {
    "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
    "kind": "purchase",
    "price_usd_cents": 1595,
    "currency": "USD",
    "plan_id": "156057",
    "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "status": "completed",
    "created_at": "2026-08-17T09:24:11.482Z"
  }
}

Responses

StatusMeaning
201The top-up was applied. `order` is null in the rare case the order row could not be re-read afterwards; the top-up itself still succeeded.
400plan_id is missing, or the Idempotency-Key header is absent or over 200 characters.
401Missing, malformed, unknown or revoked API key.
402Your balance will not cover this plan. Nothing was charged.
404No such eSIM in your account, or no plan with that id.
502The carrier refused the top-up. Your balance has already been refunded.

GET/esims/{id}/usage

Read live usage

Queries the carrier directly, so this is the authoritative number — and it is slower than the other reads. Poll it on demand, not on a tight loop. The result also refreshes the cached fields on the eSIM.

Parameters

NameInTypeDescription
idrequiredpathstringThe goAFK eSIM id.
Request
curl -X GET https://goafk.io/api/v1/esims/9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6/usage \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "usage": {
    "iccid": "8944478000001234567",
    "data_used_mb": 812,
    "data_total_mb": 5120,
    "status": "active",
    "expires_at": "2026-09-16T09:24:11.482Z"
  }
}

Responses

StatusMeaning
200Live usage.
401Missing, malformed, unknown or revoked API key.
404No such eSIM in your account.
502The carrier could not be reached. Retry; nothing was changed.

orders

Your billing history.

GET/orders

List your orders

Every charge against your balance, newest first. This is the record to reconcile your own billing against.

Parameters

NameInTypeDescription
pagequeryinteger1-based page number. Values below 1 are clamped to 1.
limitqueryintegerRows per page. Clamped to the 1–100 range.
Request
curl -X GET https://goafk.io/api/v1/orders \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "orders": [
    {
      "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
      "kind": "purchase",
      "price_usd_cents": 1595,
      "currency": "USD",
      "plan_id": "156057",
      "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
      "status": "completed",
      "created_at": "2026-08-17T09:24:11.482Z"
    }
  ],
  "total": 128,
  "page": 1,
  "limit": 50
}

Responses

StatusMeaning
200A page of orders.
401Missing, malformed, unknown or revoked API key.

GET/orders/{id}

Retrieve one order

Fetch a single order from your own history.

Parameters

NameInTypeDescription
idrequiredpathstringThe order id.
Request
curl -X GET https://goafk.io/api/v1/orders/2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b \
  -H "Authorization: Bearer $GOAFK_API_KEY"
Response · 200
{
  "order": {
    "id": "2b7c9d1e-4f60-4a23-9c81-5d6e7f809a1b",
    "kind": "purchase",
    "price_usd_cents": 1595,
    "currency": "USD",
    "plan_id": "156057",
    "partner_esim_id": "9c1f2a44-3b6e-4c88-a0d1-77e2b3c4d5f6",
    "status": "completed",
    "created_at": "2026-08-17T09:24:11.482Z"
  }
}

Responses

StatusMeaning
200The order.
401Missing, malformed, unknown or revoked API key.
404No such order in your account.

schemas

The objects returned by the endpoints above. Fields marked optional may be absent; a type ending in | null is always present but may be null.

Plan

A data plan, priced for the calling partner.

FieldTypeDescription
idstringPass this as plan_id when buying.
country_codestringISO 3166-1 alpha-2, upper case.
country_namestringEnglish country name.
regionstring | nullRegional grouping, or null for a single-country plan.
type"fixed" | "unlimited"'fixed' has a data cap; 'unlimited' does not, and reports data_gb as null.
data_gbnumber | nullIncluded data in GB. Null for unlimited plans.
duration_daysintegerValidity from activation.
price_usd_centsintegerWhat YOUR account is charged, in integer cents — wholesale plus your contracted markup. Two partners can legitimately see different prices for the same plan.
currency"USD"Always USD.

Esim

An eSIM issued to the calling partner.

FieldTypeDescription
idstringgoAFK identifier. Use this in URLs.
iccidstringThe SIM serial number.
activation_codestringThe LPA string to install the profile. Hand it to the end user verbatim, or encode it as a QR code yourself.
qr_code_urlstring | nullReady-made QR image, when the provider supplies one.
status"inactive" | "active" | "expired" | "depleted"Starts 'inactive' and becomes 'active' on first use. This field is a cached copy; call the usage endpoint for the live value.
data_total_mbintegerTotal data allowance in MB.
data_used_mbintegerCached consumption in MB.
expires_atstring | nullNull until the plan is activated.
plan_idstringThe plan this eSIM was issued from.

Order

One movement against your balance.

FieldTypeDescription
idstring
kind"purchase" | "topup"'purchase' issued a new eSIM; 'topup' added data to an existing one.
price_usd_centsintegerWhat you were charged, in integer cents.
currency"USD"
plan_idstring
partner_esim_idstring | nullThe eSIM this order produced or topped up. Null if provisioning failed.
status"completed" | "provider_failed" | "refunded"'provider_failed' means you were charged, the provider refused, and the money was automatically returned to your balance. The row is kept as an audit trail.
created_atstring

Usage

Live consumption, read from the network at request time.

FieldTypeDescription
iccidstring
data_used_mbinteger
data_total_mbinteger
status"inactive" | "active" | "expired" | "depleted"
expires_atstring | null

Error

FieldTypeDescription
errorobject

support

Questions, a new key, more balance, or a higher rate limit — write to support@goafk.io. Include the request_id from the response if you are reporting a specific failure.