Sogo Logo Developer
Get Started

Developer Documentation

Everything you need to integrate Sogo's financial services into your application. Use these guides alongside the interactive API Reference to explore every endpoint.

Account Requirements

Sandbox keys are available to accounts with at least Tier 2 KYC (identity verification) approved - start building and testing in minutes. Live keys require full Tier 3 KYC identity verification and KYB & Compliance (business verification) approval first.

RequirementSandbox keysLive keys
KYC Tier 2 (identity verification)Must be approvedMust be approved
KYC Tier 3 (identity verification)Not requiredMust be approved
KYB & Compliance (business verification)Not requiredMust be approved

To meet these key requirements:

  • KYC Tier 2 (for Sandbox & Live): Submit basic personal information and verify your identity using a valid ID number (BVN/NIN) from KYC & Limits in your Sogo profile. Approved instantly.
  • KYC Tier 3 (for Live): Submit your identity document, proof of address, and video selfie from KYC & Limits in your Sogo profile. Reviewed within 1-2 business days.
  • KYB & Compliance (for Live): Submit your business documents - CAC certificate, status report, director information, and supporting compliance documents - from KYB & Compliance in your Sogo profile. Reviewed within 1-3 business days.

Build on sandbox with instant Tier 2 KYC. Sandbox access is active as soon as Tier 2 identity verification is approved. Begin integrating immediately and swap in your live key once Tier 3 and KYB verifications are approved.

Base URLs

The Partner API has two independent environments. Use sandbox for all development and testing - it mirrors live behaviour without touching real money.

Environments
# Live
https://api.sogo.africa/v1

# Sandbox
https://sandbox.sogo.africa/v1

HTTPS is mandatory. All API requests must be made over an SSL-secured connection. Plain HTTP requests are not supported and are rejected with a 403 Forbidden response.

Key prefix determines environment. Live keys start with sogo_sk_live_ and only work on api.sogo.africa. Sandbox keys start with sogo_sk_test_ and only work on sandbox.sogo.africa. Mixing them returns a 403 environment_mismatch.

Environments (Live & Sandbox)

The Sogo Partner API operates in two environments: Live and Sandbox. The sandbox is a full-fidelity replica of the live API that lets you build, test, and debug your integration without touching real money or real utility providers. Every endpoint, request shape, response shape, error code, webhook event, and idempotency mechanism works identically to live.

AreaSandboxLive
Base URLhttps://sandbox.sogo.africa/v1https://api.sogo.africa/v1
Key prefixsogo_sk_test_ / sogo_pk_test_sogo_sk_live_ / sogo_pk_live_
Real money movementNo, wallet debits are simulatedYes
Real providers contactedNo, responses are simulatedYes
Webhooks deliveredYes, to your registered sandbox endpointYes
Wallet balanceFixed NGN 1,000,000.00 (real balance never queried)Real balance
Transaction recordsNot persisted; use the purchase response directlyPersisted
Rate limits10 req/min per key300 req/min per key

Simulating Outcomes

No real providers are contacted in sandbox.

Bills (Airtime, Data, Electricity, Cable TV, Education, Bet Funding)
Outcomes are determined by the last 4 digits of the primary customer identifier (phone, meter_number, smartcard_number, profile_id, account_id):

Last 4 digitsPurchase outcomeHTTPWebhook sent?
0000refunded201Yes, transaction.refunded
9999processing201No
Anything elsecompleted201Yes, transaction.completed

Gift Cards
Outcomes are determined by the last 4 characters of the additional_info field (for e-code cards) or the first image filename (for physical cards):

Last 4 charsTrade outcomeTransaction statusWebhook sent?
0000cancelledcancelledYes, transaction.cancelled
9999pendingpendingNo
Anything elsecompletedcompletedYes, transaction.completed

RMB Purchases (Buy orders)
Outcomes are determined by the last 4 characters of the recipient_identifier field:

Last 4 charsTrade outcomeTransaction statusWebhook sent?
0000cancelledprocessing initiallyYes, transaction.refunded
9999processingprocessing initiallyNo
Anything elsecompletedcompletedYes, transaction.completed

Crypto Sells (Test deposits)
Simulated deposits are triggered via POST /v1/crypto/test-deposit. The outcome is determined by the last 4 characters of the test_reference field:

Last 4 charsDeposit outcomeTransaction statusWebhook sent?
0000Held for compliance reviewpendingNo
9999Stuck processingpendingNo
Anything elsecompletedcompletedYes, transaction.completed

Published Test Identifiers

Copy and paste these directly into your requests:

IdentifierEndpointBehaviour
Phone 09012341234Airtime, DataSucceeds
Phone 09012340000Airtime, DataRefunded (201)
Phone 09012349999Airtime, DataStays processing
Meter 12345671234Electricity verify + purchaseSucceeds
Meter 12345670000Electricity verify + purchaseRefunded (201)
Smartcard 10001234Cable TV verify + purchaseSucceeds
Smartcard 10000000Cable TV verify + purchaseRefunded (201)
JAMB profile 12341234Education verify + purchaseSucceeds
JAMB profile 12340000Education verify + purchaseRefunded (201)
Bet account 12341234Bet funding verify + purchaseSucceeds
Bet account 12340000Bet funding verify + purchaseRefunded (201)
E-code GIFT-USA-1234Gift Card Sell (E-code)Succeeds
E-code GIFT-USA-0000Gift Card Sell (E-code)Cancelled (Webhook)
E-code GIFT-USA-9999Gift Card Sell (E-code)Stays pending
Alipay ID recipient1234RMB Buy (Alipay)Succeeds
Alipay ID recipient0000RMB Buy (Alipay)Refunded (Webhook)
Alipay ID recipient9999RMB Buy (Alipay)Stays processing
Reference DEP-TX-1234Simulate Crypto DepositSucceeds (Webhook)
Reference DEP-TX-0000Simulate Crypto DepositHeld for compliance review (Pending)
Reference DEP-TX-9999Simulate Crypto DepositStuck processing (Pending)

Sandbox transactions are not persisted. GET /v1/transactions/{reference} always returns 404 in sandbox. Use the transaction object returned directly in the purchase response. Sandbox webhooks fire to your registered sandbox endpoint only, never to live endpoints.


API Keys

Every request must be authenticated with an API key. Send it as a Bearer token in the Authorization header. Alternatively, you can use the X-API-Key header.

HTTP
POST https://api.sogo.africa/v1/bills/airtime
Authorization: Bearer sogo_sk_live_<your_key>
Content-Type: application/json

Keys are generated from your profile under the Developer tab. You can create up to 5 key pairs per environment, restrict to specific IP addresses, and scope keys to only the permissions they need.

Live keys require verification. Creating a live key requires both KYC Tier 3 and KYB & Compliance approval. See Account Requirements. If either is not yet approved, the API returns 403 kyc_tier_insufficient or 403 kyb_verification_required. Sandbox keys require KYC Tier 2 to be approved first.

Key Types

Each key pair consists of a secret key and a public key.

  • sogo_sk_live_ / sogo_sk_test_ - Secret keys. Full API access. Never expose these in client-side code, mobile apps, or public repositories.
  • sogo_pk_live_ / sogo_pk_test_ - Public keys. Restricted to read-only operations explicitly allowed for public keys. Safe to embed in client apps.

Treat secret keys like passwords. If a secret key is ever exposed, revoke it immediately from your profile and generate a replacement. Rotating a key immediately invalidates the old one.

Scopes

Scopes control which endpoints your API key can access. Assign the minimum set of scopes your integration needs - you can always add more later. The full list of available scopes is also returned by GET /v1/scopes.

ScopeAccess granted
account:readView account profile and API key context.
wallet:readView wallet balances and transaction history.
transactions:readList, retrieve, and verify transactions.
bills:readFetch bill catalogues and verify customer identifiers (meter, smartcard, JAMB).
bills:writeSubmit bill payment purchases: airtime, data, electricity, cable TV, education, ePIN, and bet funding.
gift_cards:readRead gift card catalogue, brands, and sell rates.
gift_cards:writeSubmit gift card sell orders (physical and e-code).
rmb:readRead RMB exchange rates, available channels, and order limits.
rmb:writeSubmit RMB buy orders (Alipay, WeChat Pay, Chinese bank transfer).
crypto:readRead supported crypto assets, networks, and exchange rates.
crypto:writeGenerate deposit addresses for crypto sell.

If your key is missing a required scope, the API returns 403 invalid_scope. If you send a public key to an endpoint that requires a secret key, it returns 403 secret_key_required.


Idempotency

All write operations on financial endpoints require an Idempotency-Key header. This prevents duplicate transactions if a request is retried due to a network timeout or connection drop.

HTTP
POST https://api.sogo.africa/v1/bills/airtime
Authorization: Bearer sogo_sk_live_<your_key>
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

Key rules:

  • Must be unique per operation. A UUID v4 generated client-side is the recommended format.
  • Keys are scoped to your account - the same key used by two different accounts does not conflict.
  • A key is permanently and uniquely bound to its transaction. No duplicate charge can ever be created regardless of when you retry - minutes, days, or years later.
  • Replayed responses include an Idempotency-Replayed: true header so you can distinguish them from new transactions.
  • If a request is currently in-flight with the same key, you'll receive a 409 idempotency_request_in_progress. Wait and retry.

Reconciliation: If a network error prevented you from receiving the response, use your original idempotency key to check the outcome - no retry needed:

HTTP
GET https://api.sogo.africa/v1/transactions/{idempotency-key}?type=bill_payment
Authorization: Bearer sogo_sk_live_<your_key>

A 404 means the transaction was never created and it is safe to retry with the same key. A 200 response contains the transaction - check the status field to determine next steps.

Rate Limiting

The API allows 300 requests per minute per live API key and 10 requests per minute per sandbox test API key. Exceeding this limit returns a 429 rate_limit_exceeded response. Implement exponential backoff when you receive a 429.

Monetary Amounts

All numeric amount fields in both requests and responses use major currency units (e.g. 1000 or 1000.00 for ₦1,000.00). Fields ending in _formatted are display strings only and should not be parsed.

This applies to request body amounts (e.g. amount on purchase endpoints), transaction response fields (amount.raw, fee.raw, net_amount.raw), and wallet response fields (balance, withdrawable_balance).

Note: wallets use minor units (kobo for NGN) internally. The API presents them in major units.


Integration Flows

Flow A - Bill purchase (standard)

Use this flow for all bill payment products: airtime, data, electricity, cable TV, education, ePIN, and bet funding.

  1. Discover providers. Call GET /v1/bills/catalog (optionally with ?type=) to get every supported provider, its slug, full name, and the endpoints available for that bill type. For products with variable plans (data, cable TV, education), follow up with the relevant listing endpoint (e.g. GET /v1/bills/data-plans?network=mtn) to retrieve available variation codes and pricing.
  2. Verify the customer identifier. For electricity, cable TV, and JAMB products, call the corresponding verify endpoint to confirm the meter number, smartcard number, or JAMB profile before submitting payment.
  3. Generate a UUID client-side as your Idempotency-Key. Store it before sending the request so you can use it for reconciliation if the response is lost.
  4. Submit the purchase. POST to the relevant endpoint with the Idempotency-Key header and the validated plan details.
  5. Handle the response. A 201 response contains the transaction object. Check transaction.status - the transaction may be processing (fulfilment in progress) or completed already.
  6. Track completion. Subscribe to transaction.completed and transaction.refunded webhooks, or poll GET /v1/transactions/{reference} until the status is final.
  7. Reconcile if no response was received. If a network error or timeout means you never received the API response, look up the outcome by your idempotency key before retrying:
    HTTP
    GET https://api.sogo.africa/v1/transactions/{idempotency-key}?type=bill_payment
    Authorization: Bearer sogo_sk_live_<your_key>
    A 404 means the transaction was never created - safe to retry with the same key. A 200 response returns the transaction; check status to decide next steps.

Flow B - Payment verification

Use this flow when you need to confirm that a payment already completed before fulfilling an order on your side (for example, a customer claims they paid via Sogo).

  1. Receive the transaction reference from your order flow or the customer.
  2. Call POST /v1/transactions/verify with the expected reference, amount, and currency.
  3. Gate fulfilment on verified: true in the response. A false result includes a reason field explaining the mismatch (not_found, not_completed, amount_mismatch, currency_mismatch).

Transaction Status

Every transaction has a status field reflecting its current state. Understanding each status is essential for knowing when to fulfil orders and when it is safe to retry.

StatusMeaningNext action
processing Request accepted; fulfilment is in progress with the provider. Poll GET /v1/transactions/{reference} or wait for a webhook. Do not retry.
completed Final success - service was delivered and the charge is settled. No further action needed. Safe to fulfil your order.
failed Final failure - no charge was made, or funds have already been refunded to the wallet. Retry with a new Idempotency-Key.
refunded The transaction was reversed and funds returned to the wallet. Listen for the transaction.refunded webhook event.
cancelled The transaction was explicitly cancelled. Listen for the transaction.cancelled webhook event.

Never retry on processing. The provider is actively fulfilling the request. Sending a new request with a different key risks a duplicate charge. Wait for completed or failed via webhook or polling.


Webhooks

Webhooks let Sogo push real-time transaction events to your server instead of you polling for status changes. Register up to 3 webhook endpoints from your profile's Developer tab.

Each endpoint can subscribe to one or more event types. When an event fires, Sogo makes a POST request to your URL with a JSON payload and several identifying headers.

Events

EventTrigger
transaction.completedA transaction was successfully processed.
transaction.failedA transaction failed after all processing attempts.
transaction.cancelledA transaction was cancelled (e.g. admin action).
transaction.refundedA transaction was refunded back to the customer's wallet.
pingSent when you click "Test" on a webhook endpoint.

Example payload for transaction.completed:

JSON
{
  "id": "evt_Xk9mQ2rNpL4sYv8F",
  "event": "transaction.completed",
  "created_at": "2026-05-09T08:30:00+00:00",
  "data": {
    "object": "transaction",
    "id": "8f7243e0-49c7-4f7c-a7a8-2d4e3f7ac001",
    "reference": "BILL202605090830A120123",
    "type": "bill_payment",
    "status": "completed",
    "amount": 5000.00,
    "fee": 50.00,
    "net_amount": 4950.00,
    "currency": "NGN",
    "description": "Airtime - MTN (08061464003)",
    "completed_at": "2026-05-09T08:30:00+00:00",
    "created_at": "2026-05-09T08:28:00+00:00"
  }
}

Verifying signatures

Every webhook request includes a signature so you can verify it genuinely came from Sogo. Check the X-Sogo-Signature-256 header before processing any payload.

HeaderDescription
X-Sogo-EventThe event type, e.g. transaction.completed.
X-Sogo-DeliveryUnique delivery ID for this attempt (e.g. evt_abc123).
X-Sogo-TimestampUnix timestamp of when the delivery was sent.
X-Sogo-Signature-256HMAC-SHA256 of the raw request body, prefixed with sha256=.

To verify: compute HMAC-SHA256(raw_body, webhook_secret) and compare it to the value after sha256= in the header. Use a constant-time comparison to prevent timing attacks.

PHP
$rawBody  = file_get_contents('php://input');
$secret   = getenv('SOGO_WEBHOOK_SECRET');
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
$received = $_SERVER['HTTP_X_SOGO_SIGNATURE_256'] ?? '';

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}

$event = json_decode($rawBody, true);

Always return a 2xx quickly. Sogo marks a delivery as failed if your endpoint does not respond within 15 seconds. Process events asynchronously and return 200 OK immediately.


Error Codes

When a request fails, the API returns a structured error object. Every error includes a doc_url that links directly to the relevant entry below.

JSON: error response shape
{
  "error": {
    "code": "authentication_failed",
    "message": "Invalid or revoked API key.",
    "doc_url": "https://developer.sogo.africa/docs/errors#authentication_failed"
  }
}
authentication_required 401

No API key was provided. Send your key via Authorization: Bearer <key> or the X-API-Key header.

authentication_failed 401

The API key is invalid, expired, or has been revoked. Check the key and regenerate if necessary.

https_required 403

The request was made over non-secure HTTP. All Partner API requests must be made over HTTPS. Plain HTTP requests are not supported.

environment_mismatch 403

You are using a live key on the sandbox endpoint, or vice versa. The key prefix must match the host you are calling.

ip_not_whitelisted 403

The request originated from an IP address not on the key's allowlist. Update the allowlist in your profile if your server's egress IP has changed.

invalid_scope 403

The API key does not have the scope required to access this endpoint. Create or update your key to include the necessary scope.

secret_key_required 403

This endpoint requires a secret key (sogo_sk_*). Public keys cannot access it.

idempotency_key_required 400

This endpoint requires an Idempotency-Key header. Generate a UUID client-side and include it with every write request.

idempotency_request_in_progress 409

A request with this idempotency key is already being processed. Wait a moment and retry.

rate_limit_exceeded 429

You have exceeded the requests/minute limit for your API key (300 for live, 10 for sandbox). Implement exponential backoff before retrying.

account_suspended 403

Your account has been suspended. Contact support to resolve the issue before API access is restored.

account_deactivated 403

Your account is deactivated. Log in to sogo.africa and reactivate it to restore API access.

api_disabled 503

The Partner API is temporarily unavailable. Check status.sogo.africa for updates.

sandbox_disabled 503

The sandbox environment is temporarily unavailable. The live environment is unaffected.

not_found 404

The requested resource does not exist on this account. For transactions, check that the reference or idempotency key belongs to the authenticated account.

validation_failed 422

One or more request fields are missing or invalid. Check the errors object in the response for field-level details.

insufficient_funds 422

Your wallet balance is too low to complete this transaction. Top up your wallet and retry.

verification_failed 422

Customer identifier verification failed. The meter number, smartcard number, account ID, or JAMB profile could not be validated by the provider. Double-check the value and retry.

service_unavailable 503

The requested service is temporarily unavailable. This is a transient provider-side issue. Retry after a short delay; no charge was made.

kyc_tier_insufficient 403

Your KYC Tier level is insufficient. KYC Tier 2 verification is required to use sandbox API keys, and KYC Tier 3 verification is required to use live API keys. Complete your verification from KYC & Limits in your profile.

kyb_verification_required 403

KYB & Compliance business verification must be approved before creating live API keys. Submit your business documents from KYB & Compliance in your profile. Sandbox keys are unaffected.