Checkout
-
Browse the catalog.
GET /api/v1/catalog/products?page=1&limit=20 -
Discover required checkout inputs for the variant.
Different products need different information from the buyer. Call
GET /orders/fulfillment-fields/:variantIdto get the exact set of fields to render — no guessing, no hardcoding.GET /api/v1/orders/fulfillment-fields/22402Authorization: Bearer $TOKEN{"success": true,"data": {"variant_id": 22402,"fields": [{ "name": "player_id", "label": "Free Fire Player ID", "type": "text", "required": true },{ "name": "zone_id", "label": "Zone ID", "type": "text", "required": false }],"partner_fields": [{ "partner_code": "ZENDIT", "external_offer_id": "FF_100_DIAMONDS", "required_fields": ["player_id"] }]}}Render each
fields[]entry as an input. Mark it with*whenrequired: true. -
Create the order — submit
fulfillment_inputper item.fulfillment_inputis a flat object: keys matchfields[].name, values are strings (numbers are auto-coerced). Submit only the keys for that product — mixing two identifier keys (email+uid, etc.) returns 400.Game top-up (
player_id+zone_id):POST /api/v1/ordersAuthorization: Bearer $TOKENContent-Type: application/json{"items": [{"variant_id": 22402,"quantity": 1,"fulfillment_input": { "player_id": "123456789", "zone_id": "301" }}],"payment_method": "bkash"}Gift card (email via shorthand):
POST /api/v1/ordersAuthorization: Bearer $TOKENContent-Type: application/json{"items": [{ "variant_id": 17, "quantity": 1 }],"payment_method": "bkash","recipient_email": "buyer@example.com"}The top-level
recipient_emailis a shorthand for email products — the API copies it intofulfillment_input.emailautomatically.Mixed cart (different fields per item):
POST /api/v1/ordersAuthorization: Bearer $TOKENContent-Type: application/json{"items": [{ "variant_id": 22402, "quantity": 1, "fulfillment_input": { "player_id": "123456789", "zone_id": "301" } },{ "variant_id": 17, "quantity": 1, "fulfillment_input": { "email": "buyer@example.com" } }],"payment_method": "paystation"}Each item carries its own
fulfillment_input— validated independently.Cart with a discount code:
POST /api/v1/ordersAuthorization: Bearer $TOKENContent-Type: application/json{"items": [{ "variant_id": 22406, "quantity": 1 }],"payment_method": "bkash","discount_code": "SAVE20"}Validate the code first via
GET /api/v1/discounts/validate?code=SAVE20&subtotal=500to show the customer the deducted amount before they confirm. See Discount Codes for the full validation flow and error reference.By default
POST /ordersalso initiates payment immediately (init_payment = true). The response contains the order payload and apaymentobject withpaymentGatewayUrl.{"success": true,"message": "Order created successfully","data": {"id": 42,"order_number": "12345678","status": "INITIATED","status_label": "Awaiting payment","voucher_codes": [],"dispatched_email": null,"payment": {"transactionId": "BDV-42-1730000000000-abcdef12","paymentGatewayUrl": "https://sandbox.paystation.com.bd/..."}}} -
Redirect to the payment gateway.
If you used the default inline flow above, redirect the customer to
data.payment.paymentGatewayUrl.If you need a two-step checkout, create the order with
"init_payment": false, then callPOST /api/v1/payments/initiate/:orderId. See the Payments guide for both variants. -
Wait for the gateway callback. The gateway calls back into BD Voucher (
/api/v1/payments/{gateway}/callback). We re-verify the transaction server-side, mark the paymentSUCCEEDED, and kick off fulfillment automatically. While the customer waits, pollGET /api/v1/payments/status/:transactionId. -
Deliver the voucher(s). Vouchers appear in
GET /api/v1/vouchersas soon as fulfillment succeeds.
fulfillment_input — field rules
| Error | Cause |
|---|---|
400 “only one recipient identifier is allowed” | Two identifier keys sent for one item |
400 “this product expects email but received uid” | Wrong identifier key for that product |
400 “Missing required fulfillment input … player_id” | A required field was omitted |
Values can be strings or numbers — the API coerces numbers to strings:
{ "player_id": 123456789, "zone_id": 301 }→ stored as{ "player_id": "123456789", "zone_id": "301" }Retrieve orders later
List my orders
GET /api/v1/orders?page=1&limit=10Authorization: Bearer $TOKENGet a single order
GET /api/v1/orders/:idAuthorization: Bearer $TOKENYou can also pass the 8-digit order_number instead of the numeric internal id.
Order responses expose these fields at the top level:
| Field | Description |
|---|---|
status | Raw machine-readable order status |
status_label | Short customer-friendly label |
status_message | Customer-facing copy safe to render in UI |
voucher_codes | Flat list of all codes across every item/quantity |
dispatched_email | Email address the consolidated voucher email was sent to |
email_sent_at | Timestamp of the latest successful voucher-email dispatch |
Each items[] entry also includes its own voucher_codes array.
See the API reference for the full schemas.