AfroPin Developers
Postman Sign in Get test keys

Taking payment

Check a PIN

Look up a PIN before you redeem it: its balance, currency, status and whether your account can redeem it. Nothing is debited and the PIN is not changed.

POST https://afropin.com/api/v1/brand/pins/check

HMAC-signed request with a unique Idempotency-Key header. Authentication

With an SDK
PHP$afropin->brand->pins->check($params)
Node.jsafropin.brand.pins.check(params)
Pythonafropin.brand.pins.check(params)
Javaafropin.brand().pins().check(params)

Body parameters

pin_code string Required max 64

The PIN code the customer gave you, with or without dashes. In test mode, use one of the test PINs.

amount numeric Optional > 0

The amount you intend to redeem. When given, the response says whether that exact amount can be redeemed, including the rule that single-use PINs must be redeemed in full.

fee_paid_by string Optional brand customer

Who would pay the redemption fee, as on Take payment with a PIN. With customer, redeemable_amount is the most you can redeem with the fee on top (for a single-use PIN, the exact amount to send).

Response fields

pin_mask string Required

The PIN code with its middle digits hidden, safe to show or store.

balance number Required

What is left on the PIN, in currency.

currency string Required

The PIN's currency. Redeeming credits your wallet in this currency.

status string Required active blocked expired

The PIN's status.

spend_rule string Required whole partial

whole: must be redeemed for its whole balance in one go. partial: any amount up to the balance.

can_redeem boolean Required

Whether a redeem call would succeed right now (for amount, when you sent one).

reason string | null Required

When can_redeem is false, the error code Take payment with a PIN would return, for example pin_expired or pin_not_accepted_here. With reason_message for display.

redeemable_amount number Required

The most a redeem call may pass as amount now. For single-use PINs this is the exact amount to redeem. 0 when the PIN can't be redeemed here at all.

daily_limit number | null Required

The PIN's daily spending limit, set by its customer, or null without one.

daily_limit_left number | null Required

What is left of it today (it resets at midnight, Lagos time). redeemable_amount already allows for it; an amount over it makes reason pin_daily_limit_reached.

redemption_fee_percent number Required

Your redemption fee on this PIN's product, as a percentage. 0 for test PINs.

fee_paid_by string Required brand customer

As sent (default brand).

fee number | null Required

For the amount you sent: the fee, with amount_debited (what the PIN would pay) and amount_credited (what your wallet would get). null when no amount was sent.

pin_type object | null Required

pin_type_id and name of the PIN's product. null for test PINs.

expires_at string | null Required

When the PIN expires, ISO 8601. null for test PINs.

A code that can't be found fails exactly as it would on redeem, with pin_code_unknown, pin_code_replaced or pin_checksum_failed (or test_pin_unknown in test mode). A PIN that is found but can't be redeemed by you returns 200 with can_redeem: false and the reason, so you can tell the customer before taking payment.
To stop PIN guessing, an account that looks up 20 unknown codes within 10 minutes gets rate_limited until the window passes. A successful lookup resets the count.

Request

{
    "pin_code": "2340-1000-0000-1001",
    "amount": 2500
}

Response 200

{
    "ok": true,
    "data": {
        "pin_mask": "2340-****-****-1001",
        "balance": 25000,
        "currency": "NGN",
        "status": "active",
        "spend_rule": "partial",
        "redeemable_amount": 25000,
        "redemption_fee_percent": 0,
        "fee_paid_by": "brand",
        "fee": 0,
        "amount_debited": 2500,
        "amount_credited": 2500,
        "can_redeem": true,
        "reason": null,
        "reason_message": null,
        "pin_type": null,
        "expires_at": null,
        "mode": "test"
    }
}

Response not redeemable

{
    "ok": true,
    "data": {
        "pin_mask": "2340-****-****-4004",
        "balance": 12000,
        "currency": "NGN",
        "status": "blocked",
        "spend_rule": "partial",
        "redeemable_amount": 0,
        "redemption_fee_percent": 0,
        "fee_paid_by": "brand",
        "fee": null,
        "amount_debited": null,
        "amount_credited": null,
        "can_redeem": false,
        "reason": "pin_blocked",
        "reason_message": "This PIN is blocked",
        "pin_type": null,
        "expires_at": null,
        "mode": "test"
    }
}

Errors

Failed requests return a stable code with a translated message. Branch on code, never on the message.

422 validation_error Some fields are missing or invalid
403 wrong_account_type Your account type cannot use this endpoint
403 redeeming_disabled Redeeming PINs is not switched on for your account. Contact support
422 pin_checksum_failed This is not a valid PIN code: its check digit is wrong
404 pin_code_unknown No PIN has this code
403 pin_code_replaced This code has been replaced by a newer one; ask the customer for their latest code
404 test_pin_unknown Test keys only accept the test PINs listed in the docs
429 rate_limited Too many requests. Wait a moment and try again
500 internal_error Something went wrong on our side. Try again; if it keeps happening, contact support
{
    "ok": false,
    "error": {
        "code": "wrong_account_type",
        "message": "Your account type cannot use this endpoint",
        "fields": null
    }
}
All error codes →