Getting Started
API Key Authentication
Every server-to-server call to Infinity Africa is authenticated with an API key — a long-lived credential scoped to your merchant account. There's no OAuth dance, no token refresh: generate a key once, send it on every request.
Two ways to authenticate
API key — for your backend
Send Authorization: Bearer <INFINITY_API_KEY> (or the equivalent X-API-Key: <key> header) on any request originating from your own server (a website checkout, a mobile app's backend, an ecommerce platform's order webhook). This is what these docs cover.
Dashboard session — for the Infinity Africa portal only
The merchant dashboard itself authenticates with a Supabase Auth session token, also sent as Authorization: Bearer <access_token> — Infinity Africa tells the two apart by prefix, not by header. You won't use this in your own integration — it's only relevant if you're embedding the Infinity Africa dashboard itself.
Generating a key
Full API credentials are only ever generated inside the authenticated Merchant Portal — sign in at Merchant Portal, go to API Keys, choose Sandbox or Live, name the key, and check the scopes it needs (least privilege — a checkout integration only needs collections:write, for example). There is no public endpoint to generate a key — only POST /v1/merchant/api-keys, which requires a signed-in dashboard session:
/v1/merchant/api-keysCreate an API key for your own merchant — the plaintext key is shown once, in the response.
MERCHANT_ADMIN, DEVELOPER (dashboard session){
"name": "Production checkout server",
"environment": "live",
"scopes": ["collections:write", "payment_links:read"]
}{
"success": true,
"data": {
"id": "8f14e...",
"name": "Production checkout server",
"environment": "live",
"key_prefix": "inf_live_9f2a1c3b",
"scopes": ["collections:write", "payment_links:read"],
"plaintext_key": "inf_live_9f2a1c3bd8e7...",
"status": "active",
"created_at": "2026-08-14T09:00:00Z"
}
}Copy the plaintext key now — it won't be shown again
plaintext_key is only ever returned once, on creation. Infinity Africa stores a SHA-256 hash, never the plaintext key — if you lose it, revoke it and generate a new one.Scopes
Every key is issued with an explicit set of scopes — it can only call the endpoints those scopes cover. A request with a key missing the required scope gets a 403, not a partial success.
| Scope | Grants |
|---|---|
| collections:write | Push USSD/STK/Selcom Pesa collections, generate Dynamic QR codes. |
| collections:read | Read back collection status (dashboard-scoped listing). |
| payment_links:write | Create and cancel payment links. |
| payment_links:read | Fetch a payment link by ID. |
| invoices:write | Create, edit, send, and cancel invoices. |
| invoices:read | Fetch an invoice by ID. |
| transactions:read | Look up a transaction by reference. |
| webhooks:manage | Configure the webhook URL, events, and secret. |
Sandbox vs. Live
Every key is scoped to an environment. Sandbox keys (prefix inf_sandbox_...) run against the mock payment provider — nothing settles for real, so you can build and test your entire integration risk-free. Live keys (inf_live_...) move real money. Sandbox keys never expire on their own; both can be revoked at any time.
Using your key
Attach it as a header on every request — never as a query parameter or in the request body, where it's more likely to end up logged somewhere:
GET /v1/transactions/TXN-4821AB HTTP/1.1
Host: api.infinityafrica.net
Authorization: Bearer inf_live_9f2a1c3bd8e7...Revoking a key
/v1/merchant/api-keys/{key_id}/revokeRevoke a key immediately — any request using it afterward gets 401.
MERCHANT_ADMIN, DEVELOPER (dashboard session)Rotate keys periodically from the Merchant Portal, and revoke any key that may have leaked (committed to a public repo, shared in a support ticket, etc.) immediately rather than waiting for a scheduled rotation.
Keep it secret, keep it server-side
Never ship an API key to a browser, mobile app bundle, or public repo
