AfroPin Developers
Postman Sign in Get test keys

Start here

How AfroPin works

The AfroPin API covers the whole life of a PIN: resellers issue and top up PINs, and brands redeem them at checkout. It is a JSON API over HTTPS, and every request is signed with HMAC.

Base URL

https://afropin.com/api/v1

Endpoint paths in the API reference are relative to this URL. Test and live mode share it; the API key you sign with decides the mode. Environments →

What the API covers

As a brand you accept PINs issued on the network as payment.

Balance and products

Check the wallets your redemptions credit and browse the PIN products you accept, with your redemption fee.

Redeem PINs

Take payment with a PIN at checkout. Redeem the full balance or part of it, and attribute it to a shop.

Redemption history

List every redemption your account has credited, or look one up by its reference.

Locations

Register the shops where PINs are redeemed, and look up where your customers can buy them.

Webhooks

Receive a pin.spent event for every redemption you make with a webhook attached.

Requests

  • Send request bodies as JSON with Content-Type: application/json.
  • Every request is signed with your API key and carries a unique Idempotency-Key. See Authentication.
  • IDs such as pin_id, catalog_id and webhook_id are UUIDs.
  • Write requests that move money accept an external_reference: your own ID for the operation. A reference can only be used once, so it also protects you from charging twice.
  • You can send up to 60 requests per minute. Only one write request per account is processed at a time; a second one sent while the first is running fails with rate_limited.

Responses

Every response is JSON with the same envelope. ok is true or false. A success puts the result in data (lists add paging); a failure puts code, message and fields in error.

200 Success

{
    "ok": true,
    "data": {
        "transaction_ref": "3c6bb90c-4dc9-4e01-bdf2-75e91199847d",
        "amount": 10,
        "balance": 90,
        "currency": "NGN",
        "mode": "test",
        "external_reference": "order_10293",
        "processed_at": "2026-10-05T09:14:22.000000Z"
    }
}

403 Error

{
    "ok": false,
    "error": {
        "code": "pin_blocked",
        "message": "This PIN is blocked",
        "fields": null
    }
}
  • Errors carry a stable error.code; validation errors also list each failing field in error.fields. Branch on error.code, never on error.message, which is translated into your account language. Errors →
  • Amounts are JSON numbers in the currency's main unit, for example 10 for 10 naira.
  • Timestamps are ISO 8601 in UTC.
  • Objects carry a mode field, test or live.

Storing PIN codes

We never store PIN codes
A PIN code is shown in full only once, at the moment it is created. We keep a one-way fingerprint of it (to recognise it when it is redeemed) and a masked version such as 2340-****-****-1001, never the code itself. A lost code can't be shown again by anyone, including our support team, but the value isn't lost: the reseller that sold the PIN can reissue it with a new code, for the same customer. The one exception is a webhook that carries a code and fails to deliver: that code is kept encrypted only so a resend can carry it, and is deleted as soon as a delivery succeeds or after 72 hours. Webhook logs always show codes as ****-****-****-****.
  • You never need to keep a customer's PIN code: send it to Take payment with a PIN and keep only pin_mask for your records.
  • Don't log or store the codes customers give you.

Products that issue a new code

Some products replace the PIN code after it is used, so a code that leaked earlier stops working. The product tells you which: see new_code_after_spend and new_code_after_top_up on Look up a product. When the code changes, the old code fails with pin_code_replaced and the new code is sent once:

After you redeem
new_pin_mask in the Take payment with a PIN response, when the product has new_code_after_spend. Only the mask: brands never receive the full code, so staff can't reuse a customer's PIN. Tell the customer their code has changed; they get the new one from the business they bought the PIN from.

Getting started

  1. Switch your dashboard to test mode

    API keys and webhooks belong to the mode your dashboard is in when you create them.

  2. Create a test API key

    Go to API keys and generate a key. Copy the key ID and the secret; the secret is shown only once.

  3. Sign a first request

    Call GET /brand/wallets with the code in Authentication.

  4. Add a webhook

    Register an endpoint under Webhooks so your server hears about changes. Webhooks guide

  5. Follow the integration guide, then pass UAT

    The integration guide walks through the full flow in test mode. When it works, run the Go-live checklist to request live access.

Questions, or found something that does not match these docs? Email [email protected].