Protecting your API key and secret
- Server-side only. Your API key/secret and any bearer token derived from them must never reach a browser, mobile app, or other client an end user can inspect. Exchange for a token on a server you control and proxy authenticated calls through it.
- Secrets manager, not source control. Store the key/secret in your platform’s secrets manager (AWS Secrets Manager, GCP Secret Manager, Vault, or equivalent) or, at minimum, an untracked
.envfile. Never commit them. - Transport security. Only ever call
https://api.spenza.comover TLS — never construct a plain-HTTP variant of the base URL.
Secret rotation
There is no self-service key/secret rotation endpoint in this API. If a credential may have been exposed (checked into a public repo, logged accidentally, shared over an insecure channel), contact Support immediately to have it rotated — don’t wait to confirm the exposure was exploited.Webhook credentials
Webhook registrations carry two separate secrets — don’t conflate them:authentication(the credential you configure) protects your endpoint from unauthorized callers — Spenza presents it when calling you.signingSecret(returned once, at registration) is what you use to verify a delivery actually came from Spenza, via theX-Spenza-Signatureheader. See Webhooks → Verifying delivery signatures.
signingSecret as a reason to re-register (there’s no way to retrieve it again).
Logging and sensitive-data handling
Several fields that pass through this API are sensitive and should be excluded from application logs, error-tracking tools, and analytics:- Credentials — your API secret, any bearer token, a webhook’s
authenticationcredential andsigningSecret. - Port-in carrier credentials —
currentAccountPassword(the losing carrier’s account PIN) is functionally a password; never log the request body of a port-in call unredacted. - Personal data — names, emails, phone numbers and billing addresses flow through the Users, SIMs, Devices, and Port-in surfaces. Handle this like any other customer PII in your systems: minimize retention, restrict access, and exclude it from third-party logging/analytics tools that don’t need it.
Idempotency
Many write endpoints accept anIdempotency-Key request header — use it on anything that spends money or has a side effect you can’t cheaply reverse (purchases, assignments, group membership changes). It’s the difference between “safe to retry blindly” and “must check state first.” See Core Concepts → Idempotency and Errors → Retry recommendations for the full mechanics. Not every endpoint supports it — check each operation’s page in the API Reference.
Handling rate limits
429 RATE_LIMITED means back off, not retry immediately — see Rate Limits for the full strategy (exponential backoff with jitter, applied per endpoint) and the published per-endpoint thresholds.
Request retries
Retry429 and 5xx responses with backoff; don’t retry 4xx responses unchanged — they mean the request itself needs to change. Prefer sending an Idempotency-Key on write calls over guessing whether a retry is safe. The full matrix is in Errors → Retry recommendations.
Timeout recommendations
- Synchronous endpoints (most
GET/POST/PUT/DELETEcalls) typically resolve quickly; a client timeout in the 10–30 second range is a reasonable general default. This isn’t a number Spenza publishes — size it to your own latency tolerance and adjust if you observe slower calls in practice. - Async calls (
POST /api/v1.1/esim, the/api/v3purchase variants, top-up, port-in) return immediately with atransactionId— don’t hold a long-lived connection waiting for the transaction to finish. eSIM provisioning specifically can take up to ~45 minutes end to end; pollGET /api/v3/transactions/{transactionId}on the interval described in Guides → Handling async operations instead of waiting on the original request.
Next steps
- Errors for the full error taxonomy and retry matrix.
- Rate Limits for throttling behavior.
- Webhooks for securing inbound webhook delivery specifically.

