Skip to content

Identifier Fields

Every product on BD Voucher fulfils to exactly one kind of recipient identifier. The admin chooses it when creating the product; the client API exposes it on the variant so your checkout UI can render the right form control and the API rejects mismatched submissions before the order is charged.

The four canonical keys

KeyTypical productExample value
emailGift cards, e-codes, generic voucherscustomer@example.com
player_idGame top-ups (Free Fire, MLBB, …)123456789
account_idWallet / telco recharges01711234567
uidPlatform-specific UIDs (Genshin, …)800123456

These four keys are the only identifier values allowed inside fulfillment_config.fields[].name. Sending any other identifier-like field at checkout is rejected with 400 Bad Request.

The identifier is just one of the inputs a product may need. Beyond the identifier, a product can declare any number of supporting fields (e.g. zone_id, region, phone) via the same fulfillment_config.fields[] array — see the admin guide for the schema.

Discovering a product’s identifier

Each variant in the products endpoint exposes an identifier envelope:

{
"fulfillment": {
"engine": "PRELOADED",
"identifier": {
"key": "player_id",
"label": "Free Fire Player ID",
"required": true
}
}
}

Use identifier.key to decide which input to render and identifier.label as the input’s <label> text. When required: true, your client should disable “Pay” until the field is filled.

Submitting the identifier at checkout

Pass the identifier in the per-item fulfillment_input block:

POST /orders
{
"items": [
{
"variant_id": 22402,
"quantity": 1,
"fulfillment_input": {
"player_id": "123456789"
}
}
],
"payment_method": "bkash"
}

Email products & the order-level fallback

When a product’s identifier is email, the client may either:

  1. Set fulfillment_input.email per item, or
  2. Rely on the order-level recipient_email field (the API copies it down to each email-product item automatically).

This makes single-product email checkouts trivially short:

{
"recipient_email": "buyer@example.com",
"items": [{ "variant_id": 17, "quantity": 1 }]
}

Validation rules

The order endpoint enforces the following at create time — before any payment is initiated:

  • Wrong key — supplying email for a player_id product → 400
  • Multiple keys — sending both email and player_id400
  • Missing required key — omitting the configured identifier → 400
  • Extra identifiers — silently stripped before persistence (defence in depth)

Why a single canonical key?

Earlier iterations of the platform allowed products to accept more than one identifier (e.g. “either email OR player_id”). This created two problems:

  1. Ambiguous fulfilment — partner adapters didn’t know which channel to use, leading to silent failures.
  2. Audit confusion — support couldn’t tell which identifier the customer had actually used.

Locking each product to one canonical key removed both classes of bug and lets the admin UI show a clean “Recipient” form per product instead of a tangle of conditional inputs.