Decode QR
Decodes a scanned QR string and returns the fields needed for getQuotation and executePayout.
When to use decodeQr vs lookupPaymentCode
- Use decodeQr for EMV / local QR payloads captured from a scan (or Bolivia encrypted QR).
- Use lookupPaymentCode for bank and e-wallet transfer destinations that are not QR payloads: PIX keys, phone numbers, bank account numbers, BREB keys, Africa till/paybill lookup, Vietnam account+BIN, Indonesia e-wallet phones and bank accounts, and NG/GH/ZM bank or mobile-money numbers. Calling decodeQr with those destinations returns 400
INVALID_REQUEST.
Flow
- Authenticates the request and verifies
customer_idexists under your account (registered viaregisterCustomer). - Derives routing hints from the QR, then parses and enriches the QR string for the destination corridor.
- Validates supported country/currency for the QR against your account configuration (
INVALID_COUNTRY_CODE,INVALID_CURRENCYwhen not allowed). - Computes
is_dynamicandis_businessfrom QR metadata when available, otherwise from fallback rules on the decoded data. - Creates a PENDING transaction and returns
tx_id.
Authentication
- REQUIRED: Basic Auth:
Authorization: Basic base64(client_id:client_secret). - Body-based
client_id/client_secretis deprecated and not supported. - Exchange app identity comes from authentication (do not rely on a body
exchange_app_id).
Request body
qr_string(string, required) — EMV / local QR payload. For KE/TZ a numeric till/paybill may be passed asqr_string.customer_id(string, required) — registered customer; must not contain/.partner_transaction_id(string, optional)partner_app_id(string, optional, 1–64 chars[a-zA-Z0-9_-]) — tags the transaction with a partner sub-app; body wins over the value stored on the customer.wallet_identifier(string, optional): stored on the transaction when provided.country_code(string, optional override): ISO alpha-2. Required when the QR string is not EMV-parseable:BO— Bolivia encrypted QRKE/TZ— a typed till or paybill number instead of an EMV QR (requiresmerchant_id)merchant_id(string, optional): Till or paybill number for KE/TZ when using decodeQr directly.account_reference(string, optional): Paybill bill reference when the merchant expects one.
Response (200 JSON) — curated public fields only.
is_dynamic,is_business,amount,merchant,country,tx_id,currency,partner_transaction_id(empty string if not sent)missing_fields(optional): machine-readable schemas for required data not yet satisfiedsuggested_values(optional): hints keyed by field paths for UI prefillsender/recipient(optional): grouped echoes when meaningful after decodeqr_type(Philippines):qrph_p2mfor a merchant QR,qrph_p2pfor a personal wallet QR.recipient.bank_nameandrecipient.bank_list_code(Philippines): the beneficiary institution and itscodefromlistBanks?country_code=PH, usable directly aspayment_destination_code.- Africa (KE/TZ):
merchant_id,merchant_name,payment_type(tillorpaybill),merchant_infowhen a typed till or paybill is decoded - When
amount> 0 and pricing succeeds:amount_usd,fee,percentage_fee,fixed_fee(USD values rounded to 2 decimal places).exchange_rateis not returned here (use getQuotation / executePayout).
Satisfying missing_fields:
-
amount(static QR): send the amount to getQuotation, then asamount_confirmedto executePayout. -
recipient.name(Vietnam): the name normally comes from the bank’s account-name inquiry during decode, so it is listed only when that inquiry returned nothing.recipient.bank_nois always echoed: if it is not acodeinlistBanks?country_code=VN, the destination is not payable (cardless-ATM withdrawal codes, merchant category 6011, are the common case). If the bank is listed, retry decodeQr once; if the name is still missing, passrecipient_nameat executePayout.recipient.name_first/recipient.name_lastare derived from it. -
recipient.accountorrecipient.account_noon a merchant QR: the destination could not be resolved on the payment network. Do not execute; it is rejected withMISSING_REQUIRED_FIELDSbefore any balance is locked.
Bank terminology: Prefer grouped recipient.bank_no; legacy flat keys are mapped internally.
Payout flow: decodeQr or lookupPaymentCode → getQuotation (recommended when locking fees/amount) → executePayout.
LATAM is_dynamic: Open-amount and manual-amount QRs return is_dynamic: false with amount: 0 until getQuotation supplies the amount.
Errors: CUSTOMER_NOT_ELIGIBLE, INVALID_COUNTRY_CODE, INVALID_CURRENCY, corridor amount limit violations, and INVALID_REQUEST when a typed destination is sent to decodeQr instead of lookupPaymentCode.
See Corridor Examples and lookupPaymentCode for per-country sample requests.
Authentication
Basic Auth: base64(client_id:client_secret)
Query parameters
Decimal places for monetary fields in the response (USD amounts, fees, exchange rates). Default 2, which rounds sub-cent fees to 0. Use dp=4 or higher to reconcile against exact deducted totals: at full precision amount_usd + percentage_fee + fixed_fee equals the amount deducted from your balance. Rounding is applied to the response only; all stored values and balance deductions always use full precision.
Request
EMV / local QR string, or for KE/TZ a numeric till/paybill number.
Optional partner sub-app id (1–64 chars, [a-zA-Z0-9_-]). Body value wins over the customer profile value.
ISO alpha-2 override. Required when QR is not EMV-parseable (e.g. BO encrypted QR, or KE/TZ + merchant_id).
Till or paybill number for KE/TZ, typed instead of scanned, via decodeQr. Prefer /lookupPaymentCode for the same flow.
Paybill account reference: the account, bill or customer number the paybill expects. Required for Kenya paybills (returned in missing_fields when absent); optional for TZ.
Response
Africa (KE/TZ) till or paybill number when returned.
Africa (KE/TZ) verified merchant display name when returned.
Africa (KE/TZ) payment destination type when returned.
Africa (KE/TZ) merchant metadata when returned.
