Skip to main content
Every failed API call returns code and msg in the response body. The first letter of the code tells you who has to act: The complete list is in the error code quick reference. This page covers the codes that generate the most support tickets.

I get A0001 “Invalid Api secret key” — where does the API key come from?

The X-API-KEY request header was missing or does not match a key issued to your account. The API key is provided by Waffo during merchant onboarding and is available in the Merchant Portal dashboard. Common causes:
  1. Environment mismatch — sandbox and production use different API keys and RSA keys. A sandbox key sent to https://api.waffo.com (or a production key sent to https://api-sandbox.waffo.com) fails with A0001.
  2. The X-API-KEY header is missing from the request entirely.
Fix: copy the key for the target environment from the Merchant Portal and confirm the base URL matches that environment. See Sandbox and testing.

How do I debug A0002 “Invalid signature”?

Waffo verifies the X-SIGNATURE header against the merchant public key you exchanged during onboarding, using SHA256WithRSA. Verification failing means the signature you produced does not match the body Waffo received. Work through this checklist:
  1. Sign the raw request body string exactly as transmitted — do not JSON-parse and re-stringify it, and do not sign a prettified or re-ordered copy.
  2. Confirm you are signing with the private key whose public key is registered with Waffo for this environment (sandbox and production RSA keys are separate).
  3. Confirm the algorithm is SHA256WithRSA.
  4. If you generate a new key pair, the new public key must be registered with Waffo before you switch.
The reverse direction also matters: Waffo signs every response and webhook with its private key, and you verify with the Waffo public key (Merchant Portal → Integration menu). If your verification of a Waffo response fails, stop sending new transactions and contact Waffo — your original request may already have been processed even though you could not trust the response. Code examples: webhook signature verification.

What usually triggers A0003 “Parameter validation failed”?

A0003 is a request-format rejection. The msg field carries detail; the highest-frequency causes seen in production support are:
  1. Field length exceeded. Every string field has a declared maximum — the ones merchants overflow most often on /api/v1/order/create:
  2. Amount format. Amounts are strings with at most 2 decimal places — and zero-decimal currencies such as JPY must be whole numbers. A real production example: "orderCurrency":"JPY","orderAmount":"200.88" is rejected with A0003; "201" is accepted. See currency handling.
  3. Format conventions — time is ISO 8601 with milliseconds (2023-04-01T03:00:00.000Z), currency is ISO 4217, country is ISO 3166-1 alpha-3 (IDN, PHL), and userPhone follows +CountryCode-Number, for example +62-08990013157.
Validate these locally before sending; the exact per-field contract lives in the Acquiring API Specification.

What does A0018 mean, and how do I fix it?

In the acquiring API, A0018 is “Payment method in merchant order does not match with current merchant contract” — the payMethod/country/product combination in your order is not one you have signed for. How to fix:
  1. Call /api/v1/paymethodconfig/inquiry. The response lists every contracted pay method with its productName (ONE_TIME_PAYMENT / DIRECT_PAYMENT), payMethodName, country, and currentStatus (1 available, 0 not available), plus any fixedMaintenanceRules windows.
  2. Send only combinations that appear in that list with currentStatus 1. Which methods you can sign depends on your contracted configuration — check the Merchant Portal or contact integration support to add one.
  3. Two neighbouring codes look similar but ask for more precision, not a contract change: A0022 (specify productName — multiple products found) and A0033 (specify the pay method country — multiple pay methods found).
Note: the same code is reused in the subscription API, where it signals that no payment method is available for that user to continue the charge (for example, the user has no usable bound method left). The error text is the same; only the situation differs, so read it together with the API you called.

My contract covers the payment method — why do I still get A0018 when I pass userCurrency?

A0018 also fires on the currency-pair dimension. The orderCurrency → userCurrency combination (the presentment pair) must be enabled in your contract, independently of the payment method itself. For example, an order with orderCurrency=JPY and userCurrency=USD is rejected with A0018 unless the JPY→USD pair is contracted — even when card payments are. Two ways out:
  1. Omit userCurrency. The Waffo cashier then converts the order amount into the user’s local currency automatically at the current exchange rate.
  2. Enable the pair. Contact your Waffo integration support to add the currency pair to your contract if you need to fix the user-facing currency yourself.

My order was rejected because of the amount. Where do I find the limits?

Each payment method has its own minimum and maximum order amount per currency, and some combinations carry precision rules on top of the usual currency rules (zero-decimal currencies must be whole numbers, and a few methods accept fewer decimal places than the currency normally allows). An amount outside the range or precision is rejected at order creation with an explicit error. You can read the limits programmatically: /api/v1/paymethodconfig/inquiry returns orderAmountMin and orderAmountMax for each contracted pay method, alongside its currency. Note that the response has one entry per contract rather than per pay method, so the same method can appear several times with different currencies and different limits — match on the currency you are charging in. The Merchant Portal shows the same configuration. The limits are contract-dependent fixed values: they are set when the payment method is signed for your account and do not move with exchange rates — including for cross-currency orders. To find the values that apply to you, check the payment method configuration in the Merchant Portal, or ask your Waffo integration contact.

I received E0001 “Unknown status”. Is the payment failed?

No — unknown is not final. Exxxxx errors mean the outcome is not yet determined inside Waffo or a third-party system. Treat the transaction as pending and keep querying (/api/v1/order/inquiry) until you receive a final Success/Failed status. Never show the user a failure or re-charge based on an E code alone. When retrying the original request, reuse the same paymentRequestId — it is the idempotency key. Reusing it with different parameters fails with A0011 “Idempotent param mismatch error”. See idempotency.

Waffo keeps sending me the same notification. Why?

Your endpoint is not acknowledging it. A recurring support case: a merchant’s webhook endpoint replied with Content-Type: application/octet-stream and {"message":"fail"} — so Waffo kept redelivering the notification. To acknowledge:
  1. Respond with Content-Type: application/json.
  2. Respond with body {"message":"success"} after you have processed the event. Any failed / unknown reply, non-200 status, timeout, or unparseable body triggers the retry schedule — see webhook retries.
  3. Make your handler idempotent: retries mean the same event can arrive more than once.