Skip to content

Authentication

The API uses OAuth 2.0 client credentials. You hold a long-lived client_id and client_secret; you exchange them for a short-lived access token and send that token on every request.

Terminal window
# 1. Exchange credentials for a token
curl -X POST https://partner-api.esimfo.com/oauth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "esf_test_ci_4f9c2a1b8e7d6c5a4b3f2e1d0c9b8a7f",
"client_secret": "esf_test_cs_xN2p...redacted"
}'
{
"access_token": "esf_test_at_9K3mR7pQ2wX5nB8vC1zL4jH6tY0dF...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "catalog:read orders:write orders:read esims:read"
}
Terminal window
# 2. Use the token
curl https://partner-api.esimfo.com/v1/balance \
-H 'Authorization: Bearer esf_test_at_9K3mR7pQ2wX5nB8vC1zL4jH6tY0dF...'

Tokens last one hour (expires_in: 3600). Cache the token and reuse it — do not call /oauth/token before every request.

A practical pattern: keep the token in memory with its expiry, refresh when fewer than 60 seconds remain, and refresh once more if a call ever returns token_expired.

Both the key and the token carry a prefix, and it is the prefix — not the URL — that selects the environment.

Prefix Meaning
esf_test_ci_ / esf_test_cs_ Sandbox client id and secret
esf_live_ci_ / esf_live_cs_ Live client id and secret
esf_test_at_ Sandbox access token
esf_live_at_ Live access token

This is deliberate: a sandbox key can never reach live data even if a misconfigured deployment points at the live host. See Sandbox and live.

A key carries only the scopes you granted it. Requesting an endpoint outside those scopes returns 403 insufficient_scope.

Scope Grants
catalog:read Read packages and countries
orders:read View orders
orders:write Create orders
esims:read Read eSIMs and usage, assign a customer
esims:write Top up an eSIM
balance:read View balance

You can narrow a token further by passing a space-separated scope parameter to the token endpoint. You cannot widen it beyond what the key holds.

The client_secret is shown once, at creation. We store only a hash, so a lost secret cannot be recovered — it can only be rotated.

Rotation is deliberately gentle: when you rotate, the old secret keeps working for a transition window. Deploy the new secret, confirm traffic has moved, then let the old one lapse. Nothing has to go down.

Failed token requests are throttled per client_id, so a credential-stuffing attempt against your key is rate-limited independently of your normal traffic.