{"components":{"securitySchemes":{"devKey":{"bearerFormat":"esk_live_…","description":"Self-serve developer API key minted at POST /api/v1/keys.","scheme":"bearer","type":"http"},"firebase":{"description":"Firebase ID token (esim-go-mobile project) for account endpoints.","scheme":"bearer","type":"http"}}},"info":{"contact":{"email":"support@esimgomobile.com"},"description":"The esimgomobile developer API: eSIM plans, virtual numbers, number porting, Tele Agent, billing events, and developer webhooks. Endpoints marked `x-launch: at-launch` are the frozen v1 contract — they go live with the network launch and return 404 until then. Live endpoints work today. Nothing here returns invented data: supplier-backed calls fail closed with an explicit error when credentials are absent.","title":"esimgomobile API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/api/account":{"get":{"responses":{"200":{"description":"account"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Account summary: orders, lines, numbers, Tele Agent","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/balance":{"get":{"parameters":[{"in":"query","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"remaining_mb, total_mb, percent"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Live remaining data for an eSIM line","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/catalog":{"get":{"responses":{"200":{"description":"plans"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"List live eSIM plans","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/checkout":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"plan_id":{"type":"string"}},"required":["plan_id"],"type":"object"}}},"required":true},"responses":{"200":{"description":"checkout_url"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Create a checkout session → payment URL","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/health":{"get":{"responses":{"200":{"description":"ok"}},"summary":"Liveness probe","tags":["public"]}},"/api/numbers":{"get":{"parameters":[{"in":"query","name":"country","schema":{"type":"string"}}],"responses":{"200":{"description":"numbers"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Search available virtual numbers","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/numbers/purchase":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"months":{"default":1,"type":"integer"},"number_id":{"type":"string"}},"required":["number_id"],"type":"object"}}},"required":true},"responses":{"200":{"description":"number, subscription_id"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Rent a virtual number (monthly)","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/openapi.json":{"get":{"responses":{"200":{"description":"The spec"}},"summary":"This OpenAPI document","tags":["public"]}},"/api/qr":{"get":{"parameters":[{"in":"query","name":"order_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"qr_png_url, activation_code, smdp_address"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Fetch or re-issue the eSIM QR / activation code","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/teleagent/signup":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"business":{"type":"object"},"number_id":{"type":"string"}},"required":["number_id","business"],"type":"object"}}},"required":true},"responses":{"200":{"description":"agent_id, status"},"404":{"description":"not live yet"}},"security":[{"devKey":[]}],"summary":"Attach Tele Agent to a number with business config","tags":["launch"],"x-launch":"at-launch","description":" Ships at product launch — not served yet."}},"/api/v1/billing/webhook":{"post":{"description":"Authenticity comes from the x-signature HMAC (product Secret Key), not a bearer token. Without FREEMIUS_PRODUCT_SECRET configured the endpoint refuses with 503 — verification is never faked.","responses":{"200":{"description":"recorded (mapped / unmapped / duplicate)"},"401":{"description":"invalid_signature"},"503":{"description":"webhook_unconfigured"}},"summary":"Freemius billing webhook (HMAC-signed, idempotent)","tags":["public"]}},"/api/v1/keys":{"get":{"responses":{"200":{"description":"keys"},"401":{"description":"auth_required"}},"security":[{"firebase":[]}],"summary":"List my API keys (hashes only, never secrets)","tags":["developer"]},"post":{"description":"Firebase sign-in required once — afterwards keys are self-serve (no support email, unlike Gigs' first-project gate). The raw key is returned once and never again.","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string"},"project":{"default":"production","enum":["production","test","experiment"],"type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"201":{"description":"issued"},"400":{"description":"name_required | invalid_project"},"401":{"description":"auth_required"}},"security":[{"firebase":[]}],"summary":"Mint a self-serve API key (project-scoped)","tags":["developer"]}},"/api/v1/keys/{id}/revoke":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"revoked"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"firebase":[]}],"summary":"Revoke an API key (instant)","tags":["developer"]}},"/api/v1/kyc":{"get":{"responses":{"200":{"description":"records"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"List KYC records","tags":["developer"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"country_code":{"type":"string"},"document_ref":{"type":"string"},"fields":{"type":"object"},"id_type":{"enum":["passport","national_id","drivers_license","business_registration"],"type":"string"}},"required":["country_code","id_type"],"type":"object"}}},"required":true},"responses":{"201":{"description":"record created (pending_verification)"},"400":{"description":"invalid_country_code | invalid_id_type"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Open a KYC intake record","tags":["developer"]}},"/api/v1/kyc/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"record"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Get a KYC record","tags":["developer"]}},"/api/v1/kyc/{id}/verify":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"verification outcome"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Run verification (fail-closed: kyc_verification_unavailable until a vendor is configured)","tags":["developer"]}},"/api/v1/me/numbers":{"get":{"responses":{"200":{"description":"numbers"},"401":{"description":"auth_required | invalid_token"}},"security":[{"firebase":[]}],"summary":"Caller's virtual numbers","tags":["account"]}},"/api/v1/me/orders":{"get":{"responses":{"200":{"description":"orders"},"401":{"description":"auth_required | invalid_token"}},"security":[{"firebase":[]}],"summary":"Caller's recorded billing events","tags":["account"]}},"/api/v1/me/topup":{"get":{"responses":{"200":{"description":"configured data add-ons + caller's lines"},"401":{"description":"auth_required | invalid_token"},"503":{"description":"topup_plans_unconfigured"}},"security":[{"firebase":[]}],"summary":"Data add-ons available for the caller's lines","tags":["account"]},"post":{"responses":{"200":{"description":"Freemius checkout URL for the add-on on the caller's line"},"400":{"description":"invalid_add_on | line_id_required | invalid_request"},"401":{"description":"auth_required | invalid_token"},"404":{"description":"line_not_found"},"503":{"description":"topup_plans_unconfigured"}},"security":[{"firebase":[]}],"summary":"Resolve a line + data add-on to a Freemius checkout URL","tags":["account"]}},"/api/v1/portings":{"get":{"parameters":[{"in":"query","name":"limit","schema":{"default":50,"type":"integer"}}],"responses":{"200":{"description":"portings"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"List portings","tags":["developer"]},"post":{"description":"Returns the porting with the country-specific required[] field list. Fill fields via PATCH, then POST /submit.","requestBody":{"content":{"application/json":{"schema":{"properties":{"country_code":{"description":"ISO-2","type":"string"},"direction":{"default":"in","enum":["in","out"],"type":"string"},"phone_number":{"description":"E.164","type":"string"}},"required":["phone_number","country_code"],"type":"object"}}},"required":true},"responses":{"201":{"description":"draft created"},"400":{"description":"invalid_phone_number | invalid_country_code"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Open a number-porting draft","tags":["developer"]}},"/api/v1/portings/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"porting"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Get a porting","tags":["developer"]},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"fields":{"type":"object"}},"required":["fields"],"type":"object"}}},"required":true},"responses":{"200":{"description":"updated (includes missing_required[])"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Supply porting fields (missing required fields → information_required)","tags":["developer"]}},"/api/v1/portings/{id}/submit":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"submission outcome (ok:false + porting_supplier_blocked until the voice supplier is onboarded)"},"400":{"description":"missing_required_fields"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Submit a porting to the carrier (fail-closed without supplier credentials)","tags":["developer"]}},"/api/v1/portings/{id}/transitions":{"post":{"description":"Allowed: draft→information_required|cancelled; information_required→pending|cancelled|draft; pending→completed|failed|cancelled.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"to":{"type":"string"}},"required":["to"],"type":"object"}}},"required":true},"responses":{"200":{"description":"transitioned"},"400":{"description":"invalid_transition"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Move a porting through the state machine","tags":["developer"]}},"/api/v1/status":{"get":{"responses":{"200":{"description":"status object"}},"summary":"Honest component status (derived live from configuration, never fabricated)","tags":["public"]}},"/api/v1/webhooks":{"get":{"responses":{"200":{"description":"endpoints"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"List webhook endpoints","tags":["developer"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"events":{"description":"Event types, or [\"*\"]","items":{"type":"string"},"type":"array"},"url":{"format":"uri","type":"string"}},"required":["url"],"type":"object"}}},"required":true},"responses":{"201":{"description":"registered (secret returned once)"},"400":{"description":"url_must_be_https | invalid_event_type"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"Register a webhook endpoint (HTTPS only)","tags":["developer"]}},"/api/v1/webhooks/deliveries":{"get":{"parameters":[{"in":"query","name":"endpoint_id","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":50,"type":"integer"}}],"responses":{"200":{"description":"deliveries"},"401":{"description":"auth_required"}},"security":[{"devKey":[]}],"summary":"List delivery attempts (status, attempts, errors)","tags":["developer"]}},"/api/v1/webhooks/deliveries/{id}/replay":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"requeued"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Replay a delivery","tags":["developer"]}},"/api/v1/webhooks/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"deleted"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Delete a webhook endpoint","tags":["developer"]}},"/api/v1/webhooks/{id}/rotate-secret":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"rotated (new secret returned once)"},"401":{"description":"auth_required"},"404":{"description":"not_found"}},"security":[{"devKey":[]}],"summary":"Rotate an endpoint's signing secret","tags":["developer"]}},"/api/waitlist":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"consent":{"type":"boolean"},"email":{"format":"email","type":"string"},"locale":{"default":"en","enum":["en","es","fr","de","pt","ja"],"type":"string"},"source":{"default":"site","type":"string"},"turnstile_token":{"type":"string"}},"required":["email","consent"],"type":"object"}}},"required":true},"responses":{"200":{"description":"already on the list (quiet success)"},"201":{"description":"joined"},"400":{"description":"invalid_email | invalid_locale | consent_required | turnstile_required"},"403":{"description":"turnstile_failed"}},"summary":"Join the launch waitlist","tags":["public"]}},"/api/v1/internal/events":{"post":{"summary":"Internal event ingest (voice worker → event bus)","description":"Guarded by the INTERNAL_EVENTS_SECRET shared secret (x-internal-secret header). Emits com.esimgomobile.call.started/ended and com.esimgomobile.sms.received into the developer webhook pipeline.","tags":["internal"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","data"],"properties":{"type":{"type":"string"},"data":{"type":"object"},"owner_uid":{"type":"string"}}}}}},"responses":{"200":{"description":"emitted"},"401":{"description":"bad secret"},"503":{"description":"ingest not configured"}}}}},"security":[{"devKey":[]},{"firebase":[]}],"servers":[{"url":"https://api.esimgomobile.com"}],"tags":[{"description":"No auth.","name":"public"},{"description":"Firebase ID token (esim-go-mobile project).","name":"account"},{"description":"Self-serve API key: `esk_live_…` Bearer. Mint one at POST /api/v1/keys (Firebase sign-in required once).","name":"developer"},{"description":"Frozen v1 contract — live at network launch.","name":"launch"}]}