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
| Key | Typical product | Example value |
|---|---|---|
email | Gift cards, e-codes, generic vouchers | customer@example.com |
player_id | Game top-ups (Free Fire, MLBB, …) | 123456789 |
account_id | Wallet / telco recharges | 01711234567 |
uid | Platform-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:
- Set
fulfillment_input.emailper item, or - Rely on the order-level
recipient_emailfield (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
emailfor aplayer_idproduct →400 - Multiple keys — sending both
emailandplayer_id→400 - 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:
- Ambiguous fulfilment — partner adapters didn’t know which channel to use, leading to silent failures.
- 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.