AfroPin Developers
Postman Sign in Get test keys

Bulk sales

Send a quote

Quote a business for your gift cards in bulk, at a discount. You get a pay_url for the buyer; they pay on our hosted page, and the cards are then sent from your issuing balance, as with quotes made on your Campaigns page.

POST https://afropin.com/api/v1/brand/quotes

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

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

Body parameters

catalog_id uuid Required

One of the products you sell, from Products you can sell you sell.

card_value numeric Required

The value of each card, within the product's amounts. Outside them fails with amount_too_small, amount_too_large or amount_not_offered.

quantity integer Required 1 to 1,000

How many cards.

discount_percent numeric Optional

The discount, up to the product's max_quote_discount: what resellers earn on it, so a quote never undercuts them. Above it fails with quote_discount_too_high. Defaults to 0.

company string Required max 190

The business you are quoting, shown on the payment page.

buyer_email string Required max 190

Who to send the quote to. The buyer gives their own details when paying.

message string Optional max 1000

A note for the buyer, shown on the payment page and in the email.

expires_in_days integer Optional 1 to 60

How many days the quote can be paid for, to the end of the last day. Defaults to 14.

recipients array Optional

Who gets the cards, when you already know: exactly quantity people, each with first_name, last_name and email. The buyer then only pays. Leave it out and the buyer chooses on the payment page: every card to them, or a list they upload.

webhook_id uuid Optional

A webhook to tell about this quote: quote.paid, quote.sent, quote.review, quote.expired and quote.cancelled. See Webhooks.

external_reference string Optional max 191

Your own reference, for example the deal in your CRM. Unique per mode: sending one twice fails with duplicate_external_reference.

send_email boolean Optional

true emails the quote and its link to buyer_email. Defaults to false: you send pay_url yourself.

The discount and the card payment's fee come out of your issuing balance in the product's currency, so it must cover them when the buyer pays; if it doesn't, the payment page asks them to try later and your team is emailed. The cards' full value is then paid from the buyer's payment.

Quote object

id uuid Required

The quote's ID.

reference string Required

Its QTE- reference, shown to the buyer and on your Campaigns page. Works wherever an ID does.

external_reference string | null Required

The reference you sent, for example your own order or deal number.

status string Required open paying paid sent review expired cancelled

open until the buyer starts paying, paying while they are at the payment page, paid for a moment once paid, then sent when the cards start going out. review means it was paid but the cards couldn't be sent; the money is on your issuing balance and our team contacts you. expired is an unpaid quote past expires_at; cancelled one you withdrew.

mode string Required test live

The mode of the key that made it. Test quotes are paid at once with no money taken, and send test cards.

source string Required api dashboard

Where it was made: through the API, or on your Campaigns page.

catalog_id uuid Required

The product quoted, from your issuing catalog.

pin_type string Required

The product's name.

currency string Required

The product's currency.

card_value number Required

The value of each gift card.

quantity integer Required

How many gift cards.

discount_percent number Required

The discount given.

face_total number Required

card_value × quantity: what the cards are worth.

price number Required

What the buyer pays: face_total less the discount.

company string Required

The business the quote is for.

message string | null Required

Your note to the buyer, shown on the payment page.

pay_url string | null Required

The hosted page where the buyer pays. Send it to them, or let us email it with send_email. null once the quote can no longer be paid.

delivery string | null Required recipients buyer

recipients when the cards go to a list of people (yours, or one the buyer uploaded), buyer when every card goes to the buyer. null until the buyer chooses.

recipients_count integer | null Required

How many people are on the list, when there is one. The list itself is never returned.

buyer object | null Required

name and email of whoever paid, once paid.

cards object | null Required

Once sent, the progress of the cards: status (queued, sending, stopped, done), total, sent and failed. Follow the same send on your Bulk send page.

webhook_id uuid | null Required

The webhook told about this quote's changes.

expires_at datetime Required

The end of the last day the quote can be paid.

paid_at datetime | null Required

When it was paid.

created_at datetime Required

When it was made.

Request

{
    "catalog_id": "3f8a1c2e-6b4d-4f90-8e7a-5c1d9b2e4f63",
    "card_value": 10000,
    "quantity": 50,
    "discount_percent": 5,
    "company": "Acme Ltd",
    "buyer_email": "[email protected]",
    "message": "Staff appreciation week",
    "expires_in_days": 14,
    "recipients": [
        {"first_name": "Ada", "last_name": "Obi", "email": "[email protected]"}
    ],
    "webhook_id": "ca1d075c-f6b0-4d4a-b498-d126239ee0a4",
    "external_reference": "deal-2041"
}

recipients is shortened here: it must have exactly quantity people.

Response 200

{
    "ok": true,
    "data": {
        "id": "7d0e4f2a-1c9b-4e83-a5d6-2b8f0c3e9a14",
        "reference": "QTE-K7Q2M9XW",
        "external_reference": "deal-2041",
        "status": "open",
        "mode": "live",
        "source": "api",
        "catalog_id": "3f8a1c2e-6b4d-4f90-8e7a-5c1d9b2e4f63",
        "pin_type": "Grams Fresh Bakes",
        "currency": "NGN",
        "card_value": 10000,
        "quantity": 50,
        "discount_percent": 5,
        "face_total": 500000,
        "price": 475000,
        "company": "Acme Ltd",
        "message": "Staff appreciation week",
        "pay_url": "https://afropin.com/quotes/9xQ4…",
        "delivery": "recipients",
        "recipients_count": 50,
        "buyer": null,
        "cards": null,
        "webhook_id": "ca1d075c-f6b0-4d4a-b498-d126239ee0a4",
        "expires_at": "2026-11-19T22:59:59.000000Z",
        "paid_at": null,
        "created_at": "2026-11-05T09:14:22.000000Z"
    }
}

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 issuing_disabled Issuing PINs is not switched on for your account. Contact support
404 catalog_item_not_found No item in your catalog has this catalog_id
422 amount_too_small The amount is below this product's minimum
422 amount_too_large The amount is above this product's maximum
422 amount_not_offered This product is only sold in set amounts, and this is not one of them
422 quote_discount_too_high The discount is above what resellers earn on this product (max_quote_discount in your issuing catalog)
404 invalid_webhook_id No webhook of yours has this webhook_id
422 duplicate_external_reference You have sent this external_reference before
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": "catalog_item_not_found",
        "message": "No item in your catalog has this catalog_id",
        "fields": null
    }
}
All error codes →