The one thing you cannot get from the quick reference is which API family a code belongs
to — and several codes mean different things on different families. That is the first
question below.
Does the same error code mean the same thing on every Waffo API?
No. The numeric part of a code is scoped to the API family, not global. Three codes in particular are traps:
So an
A0013 on /api/v1/payout/create means your earlier request with that
payoutRequestId is still in flight — wait, then inquire on it before submitting again; an
A0013 on /api/v1/order/cancel is terminal and must not be retried.
Always resolve a code against the family of the endpoint you called.
The prefix meaning is stable everywhere: A merchant-related, B user-related, C
system-related, D risk rejection, E unknown (keep inquiring until a final status).
Which payee fields must I send on a payout, and which go inside payoutMethodProperty?
Requirements are a matrix of receiving country × payout method, not a property of the
API. payeeFirstName, payeeMiddleName, payeeLastName and payeeIDType are declared
conditional in the specification for exactly this reason.
Two identity rules are stated outside the matrix, in the field definitions themselves:
For every other corridor the payee fields are validated downstream rather than by a
country rule, so send everything you hold. Rows are added to this matrix as corridors are
onboarded — treat it as a floor, not a ceiling, and let a rejection tell you what is
actually missing.
Which fields belong in payoutMethodProperty rather than at the top level?
payoutMethodProperty is a JSON string (max 512 characters), not an object, and it is
the only place bank routing detail is accepted:
The payee’s account identifier itself is not in
payoutMethodProperty — it is
payoutInfo.payoutMethodUserAccountNo, and its format depends on
payoutMethodType: a bank account number for BANK_ACCOUNT, and for EWALLET the
wallet’s own account number or public user identifier. payoutMethodName is the wallet
name for EWALLET and is empty for BANK_ACCOUNT.
See Payout FAQ for the create / inquire / notify loop itself.
What values can purpose take on a payout?
purpose on /api/v1/payout/create is required for payouts to mainland China and must
then be one of the values below; for other corridors it is optional and passed through to the
receiving side as supplied. The accepted values:
Pick the one that genuinely describes the payment. Some corridors — mainland China in
particular — are validated against it.
Two adjacent free-text fields are often confused with it.
description (max 128
characters) is printed on the payee’s bank or wallet statement, so keep it short: banks
and wallets truncate it, and roughly 16 English words or 10 Chinese characters is the
practical ceiling. extendInfo (max 128 characters, JSON) is echoed back to you
untouched and never reaches the payee.
Which “Optional” fields on /api/v1/order/create become mandatory for certain payment methods?
The acquiring specification marks goodsInfo, addressInfo and most of userInfo
optional, because whether they are required depends on the payment method actually used.
Aggregated by payMethodType:
Read this as sizing information, not as a contract: the same
payMethodType can differ
between markets, which is why several cells say varies by market. BNPL is the only
type that requires the full itemised basket everywhere it is offered.
If you use Waffo’s hosted cashier you can usually ignore this table. When the chosen
method needs user information you did not supply, the buyer is redirected to the cashier
and the cashier collects it. The table matters where there is no cashier in the flow.
For the authoritative pattern — submit, read the returned missing-field list, resend — and
for the full set of field paths that can be requested, see
Conditionally required fields by payment method.
What does orderAction.actionData contain?
orderAction is returned by /api/v1/order/create and /api/v1/order/inquiry when
orderStatus = AUTHORIZATION_REQUIRED, i.e. the buyer still has something to do.
actionType is WEB (redirect the buyer to webUrl) or DEEPLINK (open deeplinkUrl).
actionData is the alternative to redirecting: it carries the raw payment instrument so
you can render your own cashier page. Only the subset relevant to the chosen payment
method appears in any given response, so treat every field as optional and render what
is present.
Payment voucher fields
Amount and FX fields
Bank transfer fields
A virtual account (
bankAccount generated per order) reconciles on the account number
alone; a shared collection account reconciles on referenceNumber. If both are returned,
show both and treat referenceNumber as mandatory buyer input.
Full error code table — payout
/api/v1/payout/create, /api/v1/payout/inquiry and the payout notification.
Note what payout does not have: no
A0015–A0047. If you see one of those on a
payout endpoint, you are looking at the wrong table.
Full error code table — acquiring
/api/v1/order/create, /inquiry, /cancel, /refund, /capture,
/api/v1/refund/inquiry and the payment and refund notifications.
The acquiring family is the widest, and the
quick reference
carries additional acquiring codes beyond this specification revision. Where the two
disagree, the quick reference is the newer list.
Full error code table — subscription
/api/v1/subscription/create, /inquiry, /cancel, /manage, /change,
/change/inquiry, /update and the subscription notifications.
Two codes are unique to this family and worth handling explicitly:
A0025 (a
subscription must run for more than one period) and A0028 (asking for the management
URL before the first payment has settled).
Full error code table — withdrawal, balance and transaction limit rules
/api/v1/account/balance/inquiry, /api/v1/account/history/inquiry,
/api/v1/withdraw/consult, /create, /inquiry, the withdrawal notification, and
/api/v1/risk/transactionlimit/create, /update, /inquiry.
A0100–A0102 exist only here and appear only on the transaction limit rule
endpoints. They are not in the general quick reference, so a A0100 is not a
malformed A0010.
I received a code that is not in any of these tables. What is it?
Every code Waffo returns on a signed public API matches one of these shapes:0, or a
single letter A–E followed by four digits. A value in any other shape — a longer
string, a different prefix, a mixed alphanumeric identifier — is not part of the public
error contract and should not be branched on in your integration. Log it with the
paymentRequestId / payoutRequestId and
contact support; treat the transaction the way you would treat
E0001 until you have a definitive status from an inquiry call.
The same applies to a public-shaped code that is simply not in the table for the family
you called: inquire the order for its real status rather than inferring an outcome from
the code.