Why was my amount rejected for having too many decimals?
Because there are two precision rules, not one, and they apply to different amounts:
The second layer is where same-currency and cross-currency diverge, and it is
the part worth internalising.
Same-currency and cross-currency are checked differently. How?
The second layer is applied to whichever amount the customer is charged:- Same-currency order — the charged amount is your
orderAmount, so the strict processing precision and multiple are applied directly to what you submitted. Some currencies have a processing precision narrower than their ISO decimals: those currencies accept two decimals by the ISO rule but are processed to whole units. An amount with a fractional part in such a currency passes the first layer and is then rejected by the second. - Cross-currency order — the charged amount is the converted amount, so
the strict check lands there and not on your
orderAmount. Waffo converts, then adjusts the result to the processing currency’s precision and the payment method’s multiple, so anorderAmountcarrying decimals the processing side could not accept is no longer your problem.
orderAmount in the same currency can be accepted in one and rejected in the
other, and the difference is entirely which currency the customer pays in. If
you price in one currency and charge in another, do not carry over the
same-currency validation you built for your domestic flow.
Which direction does Waffo round the converted amount?
Up. After conversion, the amount is adjusted upward to fit the processing currency’s precision and then, where the payment method has one, upward to the next valid multiple. Rounding only ever appears in cross-currency orders — a same-currency order is never re-rounded, it is validated and passed through. The residual is reported to you: the inquiry response for a cross-currency order returns the converted amount, the rate applied, and the adjustment made, so you can reconcile the charged amount against your priced amount without recomputing it. See Exchange rates for when the rate is fixed.Why was 10.50 rejected when 10 was accepted?
Because the limit on an amount is not just a range — there is also an integer multiple. A payment method can require that the amount be a whole multiple of some unit, in which case any value that is not a multiple of it is refused regardless of how comfortably it sits inside the min/max. The multiple is dimensioned by payment method plus the currency actually being processed, so:- The same payment method can carry a multiple in one currency and none in another.
- Two payment methods in the same currency can carry different multiples.
- A method with a multiple almost always has no decimal part at all — if a
method demands multiples of a whole unit,
10.50cannot ever satisfy it.
How do I find the limits before I create the order?
Read them from the payment method query response. Each available method returnsprocessingAmountLimits, keyed by the currency being processed, with three
fields:
Both local and converted currencies appear in that map, so a cross-currency
method reports the limits in the currency the customer will actually be
charged. Validate against
multiple as well as min/max in your own
pre-flight check — that is the field most integrations skip.
Which error means which limit was hit?
Note that
A0018 is a catch-all for “nothing was available”, so it is also
what you get for a terminal mismatch or an over-long subscription. Read it as
“filtering left nothing”, not as “wrong payment method name”. See
Order creation field guide for the
other A0018 causes.
Why is a payment method unavailable to my customer?
Because a payment method’s type determines how the customer can finish, and some types can only be completed one way. A method can be restricted to specific customer terminals, and Waffo enforces that at order creation:- Waffo holds an allowed-terminal list per payment method. If the
userTerminalyou sent is not on that method’s list, the method is removed from the candidates. If nothing is left, creation fails. - App-launch-only methods are the classic case: some e-wallet, BNPL and digital banking methods complete by handing off to a mobile app, so they simply do not exist as an option on a desktop browser.
userTerminal is not a analytics hint, it is a routing
input. Sending a desktop value for a mobile session, or defaulting it to one
value for all traffic, will make perfectly available methods disappear and
produce a creation failure your logs will attribute to the wrong thing. Detect
it per session. See
Order creation field guide for the
accepted values.
Bank transfer and over-the-counter: why is nothing happening after I create the order?
Because for those types, creating the order and paying are separate events. The customer leaves with an account number, a reference or a slip, and pays later through their bank or at a counter. Nothing else happens at Waffo until they do.- Expect a long gap between creation and result, and expect two notifications: one when the order is ready to be paid and one when the money arrives.
- The window in which the customer can still pay is set per payment method, not by a single platform value, so two bank-transfer methods in the same country can close at different times.
- Do not cancel or re-create the order because it has been quiet for hours. See Confirming payment results for what counts as final.
Can I set the customer’s default card when I create the order?
No — order creation is not where the default card is set. Use the dedicated saved-payment-method endpoint; see Tokenization & card payments. What order creation does do with a saved credential is validate it strictly. PassingpaymentInfo.userPaymentAccessToken:
So a saved-card charge either goes ahead on that exact credential or it does
not go ahead at all. There is no silent fallback to another stored card, which
is deliberate: the customer must not be charged on a card you did not name.
Does tokenizationNotifyUrl replace notifyUrl?
No. They are separate channels and you need both:
notifyUrlreceives the payment result, as always.- The tokenization notification URL receives the card-binding result only.
A card was declined. Should I retry?
Only after you know which of four kinds of decline you got. Waffo maps the card scheme’s response into a Waffo failure code and a retry class:
Two rules that matter more than the taxonomy:
- A permanent decline is a card-change prompt, not a retry candidate. The most expensive integration mistake here is looping on a decline that can never clear.
- Waffo does not publish a per-code retry ceiling, and neither should your runbook assume one. Retry caps for recurring charges follow card scheme rules — see Subscription retries & payment methods.
The customer told their bank to stop the recurring payment. What must I do?
Stop all recurring deductions for that customer immediately. The schemes have specific response codes for a cardholder revoking authorization — for a single merchant or for all merchants — and for a cardholder asking that a recurring or instalment payment be stopped. These are non-retryable by definition, and continuing to attempt them is a compliance problem, not just a failed payment. Concretely:- Cancel the subscription rather than letting the retry schedule run out.
- Do not create a new subscription on the same credential.
- If the customer later wants to resume, they must authorize again from scratch, with a fresh consent.
How long does an unpaid order stay open?
There are two Waffo-side defaults, split by whether the method is a card, and neither is a contract term you should build against:
The platform defaults are environment configuration and can change; if the
window matters to your business, send
orderExpiredAt yourself on the methods
that accept a merchant-specified expiry (the Order Expiry Customization column
on Service → Payin tells you which). It is ignored on methods that do not.
See
Confirming payment results for what
orderExpiredAt does and does not control, and for why a payment can still
land after Waffo closed the order.
Stablecoin: can one payment be flagged with two exception types?
No. An exception carries exactly one type — the field is single-valued, so a payment that is both late and short is recorded under one classification, not two. The types are:
Two ordering rules you can rely on:
- Token identity is resolved before amount. An unrecognised or mismatched
token is classified as a token problem and the amount is never compared — so
do not expect an
UNDERPAIDon a transfer that was in the wrong token. - The return address is checked last, and it wins. If an exception would otherwise have been resolved automatically but the address it would return to is not a plain wallet address, the exception is re-classified as an address problem and routed to manual handling. That is why an overpayment can surface as an address exception.