AfroPin Developers
Postman Sign in Get test keys

Build your integration

Go-live checklist

The acceptance checklist to complete in test mode before live access is granted.

How to use this checklist

Work through these 75 cases with your brand test key. Each one passes when the status and the code match. Save every request and response: support asks for them before switching on live access.

2xx
Success path: the operation must work.
4xx
Expected client error: your integration must handle it, by code.
401 / 403
Authentication or permission failure.
Every request needs the full HMAC headers and a new, unique Idempotency-Key. Reusing an Idempotency-Key returns 403, so generate a new one for each call. Authentication

The redemption cases use the fixed test PINs listed in Environments.

The selling cases (SEL to LKP) use gift cards you sell yourself in test mode, from your test issuing balance. They are real test PINs, so they can't be redeemed with the fixed test PINs above. Sell your own gift cards

Signing and access SEC

# Scenario Endpoint Expected result Error code
SEC01 Leave out X-Signature GET /brand/wallets 401 Sign the request: X-Key-Id, X-Timestamp, X-Nonce and X-Signature are all required missing_auth_headers
SEC02 Sign with the wrong secret GET /brand/wallets 401 The signature does not match the request invalid_signature
SEC03 Send an X-Timestamp from 10 minutes ago GET /brand/wallets 401 X-Timestamp is more than 5 minutes away from our clock timestamp_out_of_window
SEC04 Send the same X-Nonce twice GET /brand/wallets 401 This X-Nonce has been used already; send a new one with every request nonce_replayed
SEC05 Use a key id that does not exist GET /brand/wallets 401 This API key is unknown, revoked or expired, or live access is not switched on invalid_api_key
SEC06 Leave out Idempotency-Key GET /brand/wallets 403 Send an Idempotency-Key header with every request idempotency_key_required
SEC07 Send an Idempotency-Key of 51 characters GET /brand/wallets 403 Idempotency-Key can be at most 50 characters idempotency_key_too_long
SEC08 Send an Idempotency-Key you have used before GET /brand/wallets 403 This Idempotency-Key has been used already idempotency_key_reused
SEC09 Call from an IP that is not on the key's allow-list (when you set one) GET /brand/wallets 403 Requests from this IP address are not on the key's allow-list ip_not_allowed

Wallets and catalog CAT

# Scenario Endpoint Expected result Error code
CAT01 Read your wallet balances GET /brand/wallets 200 One {amount, currency} per test wallet, including NGN —
CAT02 List your catalog, 20 per page GET /brand/catalog 200 Catalog items plus a paging block —
CAT03 List the whole catalog at once GET /brand/catalog?page=all 200 Catalog items, no paging block —
CAT04 Read one catalog item GET /brand/catalog/{catalog_id} 200 The catalog item —
CAT05 Read a catalog_id that is not yours GET /brand/catalog/{catalog_id} 404 No item in your catalog has this catalog_id catalog_item_not_found

Checking a PIN before redeeming CHK

# Scenario Endpoint Expected result Error code
CHK01 Check 2340-1000-0000-1001 for 2,500 POST /brand/pins/check 200 can_redeem true, balance 25,000, nothing changes —
CHK02 Check 2340-1000-0000-3003, the expired PIN POST /brand/pins/check 200 can_redeem false with reason pin_expired —
CHK03 Check a code that is not a test PIN POST /brand/pins/check 404 Test keys only accept the test PINs listed in the docs test_pin_unknown

Redeeming RDM

# Scenario Endpoint Expected result Error code
RDM01 Take 2,500 from 2340-1000-0000-1001 POST /brand/pins/redeem 200 Redemption successful, balance 22,500, a new code mask —
RDM02 Take the whole 15,000 from single-use 2340-1000-0000-5005 POST /brand/pins/redeem 200 Redemption successful, balance 0, a new code mask —
RDM03 Take the whole 5,000 from single-use 2340-1000-0000-6006 POST /brand/pins/redeem 200 Redemption successful, no new code —
RDM04 Redeem with your webhook_id POST /brand/pins/redeem 200 Your endpoint receives pin.spent —
RDM05 Take 1,000 from the empty PIN 2340-1000-0000-2002 POST /brand/pins/redeem 402 The PIN's balance does not cover this amount pin_balance_low
RDM06 Redeem the expired PIN 2340-1000-0000-3003 POST /brand/pins/redeem 403 This PIN has expired pin_expired
RDM07 Redeem the blocked PIN 2340-1000-0000-4004 POST /brand/pins/redeem 403 This PIN is blocked pin_blocked
RDM08 Take 4,000 from single-use 2340-1000-0000-5005 POST /brand/pins/redeem 403 This PIN is single use: the amount must be its whole balance full_balance_required
RDM09 Redeem a code that is not a test PIN POST /brand/pins/redeem 404 Test keys only accept the test PINs listed in the docs test_pin_unknown
RDM10 Send an external_reference you have used before POST /brand/pins/redeem 422 You have sent this external_reference before duplicate_external_reference
RDM11 Leave out amount POST /brand/pins/redeem 422 Some fields are missing or invalid validation_error
RDM12 Send a webhook_id that is not yours POST /brand/pins/redeem 404 No webhook of yours has this webhook_id invalid_webhook_id
RDM13 Send a store_id that is not yours POST /brand/pins/redeem 422 No store of yours has this store_id invalid_store_id
RDM14 Leave out store_id when your account requires a store POST /brand/pins/redeem 422 Some fields are missing or invalid validation_error
RDM15 Redeem into a currency you have no wallet for POST /brand/pins/redeem 403 Your account has no wallet in this currency currency_not_supported

Redemption history HST

# Scenario Endpoint Expected result Error code
HST01 List your redemptions GET /brand/payments 200 Redemptions in your key's mode, plus a meta block —
HST02 List one day's redemptions GET /brand/payments?day=YYYY-MM-DD 200 Only that day —
HST03 Ask for page 2, one per page GET /brand/payments?page=2&limit=1 200 paging.page is 2 —
HST04 Ask for page 0 GET /brand/payments?page=0 422 Some fields are missing or invalid validation_error
HST05 Read one redemption by the transaction_ref redeem returned GET /brand/payments/{ref} 200 The redemption —
HST06 Read a reference that is not yours GET /brand/payments/{ref} 404 No transaction of yours has this reference transaction_not_found

Products you sell SEL

# Scenario Endpoint Expected result Error code
SEL01 List the products you sell GET /brand/issuing-catalog 200 Your own products, sale_commission_percent 0 —
SEL02 Read one of them GET /brand/issuing-catalog/{catalog_id} 200 The product —
SEL03 Read a catalog_id you don't sell GET /brand/issuing-catalog/{catalog_id} 404 No item in your catalog has this catalog_id catalog_item_not_found

Issuing PINs ISS

# Scenario Endpoint Expected result Error code
ISS01 Issue an amount the product allows; keep pin_id and pin_code POST /brand/pins 200 Voucher Created, status active, mode test —
ISS02 Issue with your webhook_id POST /brand/pins 200 Your endpoint receives pin.sold —
ISS03 Issue less than the product minimum POST /brand/pins 422 The amount is below this product's minimum amount_too_small
ISS04 Issue more than the product maximum POST /brand/pins 422 The amount is above this product's maximum amount_too_large
ISS05 Issue an amount a fixed-amount product does not sell POST /brand/pins 422 This product is only sold in set amounts, and this is not one of them amount_not_offered
ISS06 Issue more than your test issuing balance holds POST /brand/pins 402 Your wallet balance does not cover this amount wallet_balance_low
ISS07 Issue a catalog_id that is not yours POST /brand/pins 404 No item in your catalog has this catalog_id catalog_item_not_found
ISS08 Send an email address that is not valid POST /brand/pins 422 Some fields are missing or invalid validation_error
ISS09 Send phone without phone_code POST /brand/pins 422 Some fields are missing or invalid validation_error
ISS10 Send a webhook_id that is not yours POST /brand/pins 422 No webhook of yours has this webhook_id invalid_webhook_id
ISS11 Send a store_id that is not yours POST /brand/pins 422 No store of yours has this store_id invalid_store_id
ISS12 Send an external_reference you have used before POST /brand/pins 422 You have sent this external_reference before duplicate_external_reference
ISS13 Issue a product in a currency you have no wallet for POST /brand/pins 403 Your account has no wallet in this currency currency_not_supported
ISS14 Sell with your brand key on the reseller path POST /reseller/pins 403 Your account type cannot use this endpoint wrong_account_type

Topping up TOP

# Scenario Endpoint Expected result Error code
TOP01 Top up a PIN you issued POST /brand/pins/top-up 200 Voucher Topped Up, higher balance —
TOP02 Top up a PIN type that cannot be topped up POST /brand/pins/top-up 403 This PIN type cannot be topped up topup_not_allowed
TOP03 Top up past the product maximum POST /brand/pins/top-up 422 The amount is above this product's maximum amount_too_large
TOP04 Top up a blocked PIN POST /brand/pins/top-up 403 This PIN is blocked pin_blocked
TOP05 Top up an expired PIN POST /brand/pins/top-up 403 This PIN has expired pin_expired
TOP06 Top up a pin_id that is not yours POST /brand/pins/top-up 404 No PIN has this id pin_not_found
TOP07 Send an external_reference you have used before POST /brand/pins/top-up 422 You have sent this external_reference before duplicate_external_reference

Blocking, unblocking, new codes and webhooks CTL

# Scenario Endpoint Expected result Error code
CTL01 Block an active PIN POST /brand/pins/block 200 Voucher disabled —
CTL02 Block it again POST /brand/pins/block 409 This PIN is already blocked pin_already_blocked
CTL03 Unblock it POST /brand/pins/unblock 200 Voucher activated —
CTL04 Unblock it again POST /brand/pins/unblock 409 This PIN is already active pin_already_active
CTL05 Unblock an expired PIN POST /brand/pins/unblock 403 This PIN has expired pin_expired
CTL06 Give a PIN a new code POST /brand/pins/new-code 200 Voucher code reissued; the old code stops working —
CTL07 Point a PIN at another of your webhooks POST /brand/pins/webhook 200 Voucher webhook updated —
CTL08 Point it at a webhook_id that is not yours POST /brand/pins/webhook 404 No webhook of yours has this webhook_id invalid_webhook_id
CTL09 Have us deliver to a PIN's customer POST /brand/pins/delivery 200 handle_delivery saved; a new code then reaches the customer by email —

Looking up PINs LKP

# Scenario Endpoint Expected result Error code
LKP01 Read a PIN you sold GET /brand/pins/{id} 200 Balance, status, code masks and customer —
LKP02 Read a PIN id that is not yours GET /brand/pins/{id} 404 No PIN has this id pin_not_found
LKP03 List a PIN's movements GET /brand/pins/{id}/movements 200 Movements plus a meta block —
LKP04 Ask for page 2, one per page GET /brand/pins/{id}/movements?page=2&limit=1 200 paging.page is 2 —

Requesting live access

When every case above passes in test mode:

  1. Get your KYC approved

    Live keys only work once your business is verified.

  2. Send your evidence to support

    Share the captured requests and responses for each case. [email protected]

  3. Create live credentials

    Once live access is granted, switch the dashboard to live mode and create a live API key and webhook. The same requests work unchanged. Environments