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:
-
Get your KYC approved
Live keys only work once your business is verified.
-
Send your evidence to support
Share the captured requests and responses for each case. [email protected]
-
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