- Payin Agreements & Transaction Limits — the same configuration as the Portal renders it, on Service → Payin: every column, the fee notation, agreement statuses, filters and export.
- Limits, Currency & Configuration Errors —
which limit each of
A0008/A0020/A0021refers to, and how the daily ceiling is counted. - Conditional & Required Fields — which order-creation fields become mandatory for which kind of payment method.
How do I find out from code which payment methods my account can use?
Call/api/v1/paymethodconfig/inquiry. It takes one meaningful field:
The response is your merchant ID plus
payMethodDetails, an array with one
entry per payment method contract that is currently in force on your account.
Treat this endpoint as the source of truth for your own integration logic —
which methods to offer, which currencies to accept, what amount range to
validate against before you create an order — rather than hardcoding a list you
copied out of a specification once.
What does each field in the response mean?
Two parsing rules worth building in from the start:
- Amounts are strings, not numbers. Parse them as decimals; do not let a JSON library turn them into floats.
orderAmountMin/orderAmountMaxcan be absent. Where a contract has no range configured, the field is simply not populated, and no amount-range check applies to that contract.
Why does the same payment method appear more than once?
Because the array is keyed on contracts, not on payment methods. One entry is emitted per contract in force, and a single payment method can legitimately be under several: one per currency, or one per payin product. SopayMethodName is not a unique key in this response. If you are building
a lookup table, key it on the combination you actually need — typically
payMethodName + currency, or productName + payMethodName + currency.
Nothing in the response is de-duplicated for you.
currentStatus came back empty. Is the payment method down?
No — an empty currentStatus means “not known right now”, not “unavailable”.
The contract data and the real-time availability come from two different places.
The contract half is always present. The availability half is looked up
separately, and where that lookup does not cover a contract, currentStatus,
fixedMaintenanceRules and fixedMaintenanceTimezone are all left unset for
that entry rather than being guessed at.
How to handle it:
The last row matters most: a client that reads “empty” as “off” will hide
perfectly working payment methods the moment an availability lookup has a bad
minute. The authoritative answer to “can this method take this payment” is
always the response to order creation.
Does the response include contracts that have ended?
No. The query behind this endpoint selects only contracts that are inACTIVE
status and whose validity window covers the current moment — a start date at
or before now, and either an end date at or after now or no end date at all.
Consequences:
- Contracts in
INIT,SUSPENDED,TERMINATEDorON_BOARDINGstatus do not appear. - A contract that has not started yet, or whose end date has passed, does not appear.
- A payment method disappearing from the response is therefore a contract
event, not an availability blip. A method that is contracted but temporarily
unusable stays in the response with
currentStatusof0.
currentStatus. Do not use one to answer the other.
Agreement statuses as the Portal shows them are described in
Payin Agreements & Transaction Limits.
What do the four refundAllowed values mean?
They describe the shape of refund the payment method permits — not whether
any particular order can be refunded right now.
The Portal renders the same four values as No, Only Full Refund, Full
Refund or One-time Partial Refund and Full Refund or Multiple Partial
Refunds.
Two things this value does not tell you:
- Whether the refund window is still open. That is a separate setting; see Payment Method Refunds & Limits.
- Whether the order is in a refundable state. An unpaid or already fully
refunded order is refused regardless of
refundAllowed.
What are fixedMaintenanceRules, and how do I read them?
They are the payment method’s scheduled unavailability windows: each rule is
a pair of cron expressions, startRule and endRule, marking the beginning and
the end of a window. fixedMaintenanceTimezone is the timezone they are
evaluated in — it is often not your own, so read it rather than assuming.
Typical shapes:
These are known in advance, so they are the one part of availability you can
usefully pre-empt in your UI. Unscheduled outages show up as
currentStatus of
0 instead, with no advance notice.
How do I check the amount range before I create an order?
ReadorderAmountMin and orderAmountMax off the matching entry — matching on
payment method and currency, since the range is per contract and two
currencies under the same method can have different ranges.
Validating client-side saves your customer a rejected order, but it is not the
only ceiling. There are three separate limits, with three separate error codes,
and this endpoint only exposes the first:
They are independent: passing the payment method’s range says nothing about the
account-level limits, and vice versa. The full breakdown, including how the
daily total is counted and when headroom comes back, is in
Limits, Currency & Configuration Errors.
I got a parameter error that mentions my merchant ID. What is wrong?
Every signed endpoint checks themerchantId in your request body against
the merchant ID that the API key you signed with belongs to. If they differ,
the request is refused before anything else happens, with the reason
mid in params is inconsistent with apiKey, returned under A0003.
This is deliberately a distinct message rather than a generic parameter error,
because the two causes are so different from every other parameter problem:
It never means the merchant ID does not exist, and it is never fixed by
retrying.
A0003 came back. How do I find out which field was wrong?
Read the message, not just the code. For A0003 specifically, the specific
reason is appended to the generic message in parentheses:
A0003
comes back with HTTP 400.
Two implications for your error handling:
- Log the whole message, not the code. A log line that records only
A0003has thrown away the only part that identifies the bug. - Do not parse the parenthesised text programmatically. It is written for a human reading a log. Branch on the code; show the text.
A0003 return their standard message with no appended detail,
unless the specific failure is one that is defined to carry extra context.
What are the rules for my callback URL?
notifyUrl — the URL Waffo posts payment notifications to — is validated when
you configure it, and each failure mode has its own error:
Both are returned under
A0003, with the specific reason in the message as
described above.
The two that catch people out are the last two. A URL with a non-ASCII character
in it — an internationalised domain name, or a path segment pasted from a
document — is refused even though a browser would open it: percent-encode it
first. And a trailing space picked up while copying is enough to fail the
whitespace check, with an error that looks like it is about the URL itself.
Leaving notifyUrl empty is allowed; no validation runs and no notifications
are sent to it.
Do I have to send subscriptionManagementUrl, and where does it end up?
It is documented as required when you create a subscription, and is capped
at 256 characters — but note that the create call today only enforces the
length: a request without it is not rejected. Treat it as required anyway,
because on one account setting (below) it is the only management link your
customer will ever get. What it is for, and why it should be a page that opens in
a desktop browser rather than an app deeplink, is covered in
Subscription FAQ.
The part that page does not cover is which management link your customer
actually receives. That is an account-level setting with two values:
Two consequences:
- On
MERCHANT_API_URL, your value is the link. If you did not send one, or sent a page that has since moved, the link in your customer’s email is broken and nothing else compensates for it. Read it back on subscription inquiry to confirm what is stored. - On
INTERNAL, links from older emails stop working. Each new email generates a fresh link and invalidates the previous ones, so a customer digging out last month’s email will need the latest one instead. The generated link is also time-limited in its own right.
Which columns changed in my transaction and refund exports?
Three changes, and one of them is easy to misread:
The trap is the third row.
Merchant Original Order ID is defined on the shared
column set but is deliberately excluded from the transaction export — it
only means something on a refund row, where it distinguishes your ID for the
refund from your ID for the payment it reverses. If your transaction export
parser is looking for it, it will not find it.
On Initiation Type: it is frequently empty. Why, and what populates it, is in
Transaction & Refund Field Reference.
Exports are queued background tasks rather than instant downloads — see
Exports & Report Downloads.
Can I narrow the chargeback or refund lists to one subscription or one order?
Yes, and these are the filters people most often miss:merchantOriginalOrderId is the one to reach for when a customer disputes a
purchase and you know only your own order reference: it goes straight from your
order ID to every refund against that payment, without having to look up Waffo’s
identifiers first.
Note the naming. The filter is relatedSubscriptionId, not subscriptionId —
“related” because the row being filtered is a chargeback, refund or payment that
came from a subscription, not the subscription itself. To list subscriptions,
filter a subscription list on acqSubscriptionId or
merchantSubscriptionId instead.
A customer reopened an old checkout link. What do they see?
A checkout link is a session, and sessions do not last forever. Two separate lifetimes apply:- Before payment, the link is valid for a limited period from creation. Opened after that, it reports the checkout as expired rather than taking a payment.
- After the order reaches a final state, the link stops being a payment page and becomes a result page, viewable for a period after completion, then no longer.