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.
HMAC-signed request with a unique Idempotency-Key header. Authentication
$afropin->brand->quotes->create($params)afropin.brand.quotes.create(params)afropin.brand.quotes.create(params)afropin.brand().quotes().create(params)Body parameters
One of the products you sell, from Products you can sell you sell.
The value of each card, within the product's amounts. Outside them fails with amount_too_small, amount_too_large or amount_not_offered.
How many cards.
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.
The business you are quoting, shown on the payment page.
Who to send the quote to. The buyer gives their own details when paying.
A note for the buyer, shown on the payment page and in the email.
How many days the quote can be paid for, to the end of the last day. Defaults to 14.
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.
A webhook to tell about this quote: quote.paid, quote.sent, quote.review, quote.expired and quote.cancelled. See Webhooks.
Your own reference, for example the deal in your CRM. Unique per mode: sending one twice fails with duplicate_external_reference.
true emails the quote and its link to buyer_email. Defaults to false: you send pay_url yourself.
Quote object
The quote's ID.
Its QTE- reference, shown to the buyer and on your Campaigns page. Works wherever an ID does.
The reference you sent, for example your own order or deal number.
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.
The mode of the key that made it. Test quotes are paid at once with no money taken, and send test cards.
Where it was made: through the API, or on your Campaigns page.
The product quoted, from your issuing catalog.
The product's name.
The product's currency.
The value of each gift card.
How many gift cards.
The discount given.
card_value × quantity: what the cards are worth.
What the buyer pays: face_total less the discount.
The business the quote is for.
Your note to the buyer, shown on the payment page.
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.
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.
How many people are on the list, when there is one. The list itself is never returned.
name and email of whoever paid, once paid.
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.
The webhook told about this quote's changes.
The end of the last day the quote can be paid.
When it was paid.
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.
validation_error
Some fields are missing or invalid
wrong_account_type
Your account type cannot use this endpoint
issuing_disabled
Issuing PINs is not switched on for your account. Contact support
catalog_item_not_found
No item in your catalog has this catalog_id
amount_too_small
The amount is below this product's minimum
amount_too_large
The amount is above this product's maximum
amount_not_offered
This product is only sold in set amounts, and this is not one of them
quote_discount_too_high
The discount is above what resellers earn on this product (max_quote_discount in your issuing catalog)
invalid_webhook_id
No webhook of yours has this webhook_id
duplicate_external_reference
You have sent this external_reference before
rate_limited
Too many requests. Wait a moment and try again
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 →