Skip to content

Checkout

  1. Browse the catalog.

    GET /api/v1/catalog/products?page=1&limit=20
  2. Discover required checkout inputs for the variant.

    Different products need different information from the buyer. Call GET /orders/fulfillment-fields/:variantId to get the exact set of fields to render — no guessing, no hardcoding.

    GET /api/v1/orders/fulfillment-fields/22402
    Authorization: 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 * when required: true.

  3. Create the order — submit fulfillment_input per item.

    fulfillment_input is a flat object: keys match fields[].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/orders
    Authorization: Bearer $TOKEN
    Content-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/orders
    Authorization: Bearer $TOKEN
    Content-Type: application/json
    {
    "items": [{ "variant_id": 17, "quantity": 1 }],
    "payment_method": "bkash",
    "recipient_email": "buyer@example.com"
    }

    The top-level recipient_email is a shorthand for email products — the API copies it into fulfillment_input.email automatically.

    Mixed cart (different fields per item):

    POST /api/v1/orders
    Authorization: Bearer $TOKEN
    Content-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/orders
    Authorization: Bearer $TOKEN
    Content-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=500 to show the customer the deducted amount before they confirm. See Discount Codes for the full validation flow and error reference.

    By default POST /orders also initiates payment immediately (init_payment = true). The response contains the order payload and a payment object with paymentGatewayUrl.

    {
    "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/..."
    }
    }
    }
  4. 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 call POST /api/v1/payments/initiate/:orderId. See the Payments guide for both variants.

  5. 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 payment SUCCEEDED, and kick off fulfillment automatically. While the customer waits, poll GET /api/v1/payments/status/:transactionId.

  6. Deliver the voucher(s). Vouchers appear in GET /api/v1/vouchers as soon as fulfillment succeeds.


fulfillment_input — field rules

ErrorCause
400 “only one recipient identifier is allowed”Two identifier keys sent for one item
400 “this product expects email but received uidWrong 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=10
Authorization: Bearer $TOKEN

Get a single order

GET /api/v1/orders/:id
Authorization: Bearer $TOKEN

You can also pass the 8-digit order_number instead of the numeric internal id.

Order responses expose these fields at the top level:

FieldDescription
statusRaw machine-readable order status
status_labelShort customer-friendly label
status_messageCustomer-facing copy safe to render in UI
voucher_codesFlat list of all codes across every item/quantity
dispatched_emailEmail address the consolidated voucher email was sent to
email_sent_atTimestamp 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.