Skip to main content
Changes that affect what you send us or what we send back. Entries are newest first. A Breaking entry needs a code change before you take the release; everything else is additive.
Breaking changes are announced here and applied to both environments. Exercise them in the sandbox — it runs fully simulated provider rails — before updating your production integration.

2026-10-15

Per-customer developer fees can be set with an API key

PUT and DELETE /v1/customers/{id}/developer-fees no longer return 403 step_up_required to a call made with a secret API key, so you can set a customer’s developer fee straight after creating the customer through the API. A change made in the console still asks for your second factor. The fees:write scope, the fee caps and the audit trail are unchanged. Your global fee (PUT /v1/developer-fees) still has to be changed in the console. Migration. None.

2026-10-14

Conversion quotes no longer need a funded wallet

POST /v1/treasury/conversion-quotes now prices a conversion even when the wallet’s available balance does not cover it, so you can show a price before the account deposits. Quotes carry a new boolean, sufficientBalance: whether the available balance covered sourceDebit when the quote was priced. Quotes also carry inverseRate, the reciprocal of rate, for showing the price the other way round. Accepting a quote with sufficientBalance: false returns 422 insufficient_balance, even if funds land in the meantime; fund the wallet and request a new quote. Migration. If you relied on the quote request returning 422 insufficient_balance, read sufficientBalance on the quote instead. Accepting a quote still refuses an unfunded wallet with the same error.

AUD funding accounts register your account name

A new aud_account funding instrument registers its accountName with the bank alongside your company name, so a payer’s Confirmation of Payee check matches the name you chose. payeeName on those instruments is now your accountName. Instruments created earlier keep your company name as payeeName; the bank cannot add a name to an existing account, so create a new instrument to use a different name. Migration. None.

2026-10-11

Transfers carry the exchange rate and your developer fee

Transfers now include two fields once the conversion has executed, on GET /v1/transfers, GET /v1/transfers/{id} and the transfer.* webhooks:
  • exchangeRate: destination units per one source unit the conversion executed at, before your developer fee. A decimal string.
  • developerFee: { "amount": "1.25", "currency": "AUD" }, the developer fee withheld from this conversion. A zero fee reads "0.00". It is omitted on a returned, reversing or reversed transfer.
Both fields are absent before the conversion executes. Migration. None. The fields are additive.

API keys show when they were last used; fee schedules show who changed them

  • API keys in GET /v1/api-keys now include lastUsedAt and lastUsedIp: when the key last authenticated a request, and the client IP it came from. Both are null until the key is used. They update at most once a minute.
  • GET /v1/developer-fees now includes updatedByName: the email of the team member who made the last change from the console, or Wayex for a change made by Wayex. It is null for a change made with an API key alone, and always null when you read with a publishable key.
Migration. None. The fields are additive.

Date and status filters for transfers and customers

  • GET /v1/transfers now applies from / to (inclusive bounds on the creation time, ISO 8601 with an offset).
  • GET /v1/customers now applies status (one verification status or a comma-separated list).
Before this, these parameters were accepted and ignored for your keys. Migration. If you already send these parameters, results are now narrowed by them. A malformed value now returns 400: on transfers, an unparseable from or to, or from later than to; on customers, an unknown status (invalid_status).

Webhook secret rotation keeps the old secret for 24 hours

For 24 hours after you rotate a webhook signing secret, each delivery is signed with both secrets. The new secret signs X-Wayex-Signature and X-Wayex-Signature-Timestamp as before. The previous secret signs two extra headers, X-Wayex-Signature-Previous and X-Wayex-Signature-Timestamp-Previous, in the same formats. Subscriptions in GET /v1/webhooks show previousSecretExpiresAt while the overlap is open. See Rotate the signing secret. Migration. None. To rotate without dropping deliveries, accept a delivery when either signature matches a secret you hold.

Sandbox API keys start sk_test_ and pk_test_

New keys created in the sandbox start sk_test_ / pk_test_. Production keys still start sk_live_ / pk_live_. API key responses now include environment (live or test). Migration. None. Existing keys keep working whatever their prefix. If your code checks for sk_live_, also accept sk_test_ for sandbox keys.

Off-ramp transfers start at deposit_detected

A transfer funded by a stablecoin deposit on an off-ramp route is now created at deposit_detected, because the deposit has already arrived. transfer.created carries deposit_detected, and no separate transfer.updated for deposit_detected follows. Transfers created before this change are unaffected. Migration. If you wait for a transfer.updated with deposit_detected, read the status from transfer.created as well.

Closed payment routes

A payment route closed from the console no longer converts new payments. A payment that lands on a closed route is placed on_hold with references.lastCaseReason set to route_inactive, and Wayex contacts you to resolve it. POST /v1/transfers/{id}/progress returns 409 route_inactive for a transfer on a closed route; refund the payer with POST /v1/transfers/{id}/refund instead. Migration. Treat route_inactive as a known lastCaseReason and 409 code.

2026-10-08

Hold on-ramp payments for your approval

On-ramp payment routes can now hold each payment for your approval instead of converting it automatically. Once Wayex enables the capability for your account, create an AUD-to-stablecoin route with clientGate: true, or turn it on for an existing route with PUT /v1/payment-routes/{id}/client-gate. Each payment on that route clears screening and then waits at awaiting_client_action until you call POST /v1/transfers/{id}/progress (convert at the live rate at that moment) or POST /v1/transfers/{id}/refund (return the full AUD amount to the payer; your Wayex transfer fee applies). On-ramp routes now also return clientGate and clientGateActive once the gate has been turned on. Migration. Two new transfer statuses, awaiting_client_action and refunding, appear only on routes where you enable clientGate (capability enabled by Wayex). Clients with exhaustive status enums should add them. API keys holding the transfers:write scope can now progress and refund client-gated transfers; review keys that hold it.

2026-10-07

Per-customer developer fees

New GET, PUT and DELETE /v1/customers/{id}/developer-fees set a developer fee override for one of your customers. The override replaces your global developer fee for that customer (send {} to charge them none); removing it returns them to your global fee. Same caps as the global fee. New GET /v1/developer-fees/customers lists the customers that have an override (a custom fee, or waived), most recently updated first, with cursor pagination. Migration. None. The endpoints are additive; customers without an override keep your global fee.

2026-09-11

On-ramp deposit instructions carry the account name to enter

An aud_to_stablecoin route’s instructions.deposit now includes payeeName: the account name the payer enters alongside the BSB and account number. It is the customer’s verified name (the name on their KYC/KYB record), and it is registered on the virtual account together with your company name, so the payer’s bank confirms the payee when they enter either. The instruction steps name it too. Before this, the account was registered under your company name only, so a customer entering their own name failed their bank’s payee check and could only pay by entering “Wayex”. Migration. None. The field is additive and only present on routes created from this release. Routes created earlier carry no customer name on the account: keep telling those payers to enter “Wayex”. Re-create the route to get a named account.

2026-09-04

Breaking · AUD payout destinations are format-checked at creation

POST /v1/payment-routes and POST /v1/customers/{customerId}/payment-routes now validate an AUD destination when you create the route, not when the payout is built:
  • bsb must be six digits, plain or hyphenated — 062000 and 062-000 are both accepted and both stored as 062000.
  • accountNumber must be one to nine digits.
  • A PayID value must be a plausible alias of its declared type (an email address, a phone number of 8–15 digits, or an 11-digit ABN). Spaces, brackets and hyphens are tolerated and normalised.
Before this, a malformed destination was accepted and only refused at the bank rail — after your customer had already funded the route and the conversion had happened. Now it is a 400 on the create call. Migration. Nothing changes if you already send well-formed details. If you pass through user-entered bank details, validate or normalise them before you create the route.

Transfer holds and returns are easier to follow

  • GET /v1/transfers takes two new query parameters: status (one value or a comma-separated list of lifecycle statuses; an unknown value is a 400) and hold_reason (the machine code on references.payoutHoldReason or references.lastCaseReason). Pull the held or failed set directly instead of paging everything and filtering client-side.
  • A payment returned after the transfer completed — an AUD payout sent back by the receiving bank, or a returned pay-in — now finishes at reversed on both corridors. The transfer passes through returned and reversing on the way; treat those two as still in flight and reversed as the end state.
  • references.lastCaseReason and references.lastCaseAt report why a transfer is parked and when. Where the hold is something Wayex has to clear rather than anything about your request, the code reads manual_or_provider_review and needs no action from you.

Treasury account names are capped at 140 characters

accountName on Treasury AUD funding instruments and on bank-account and PayID beneficiary destinations is now limited to 140 characters and must contain at least two printable characters. The bank rail cannot carry more, so an unrenderable name is now a 400 at create time instead of a payout that reserves your funds and then parks.

2026-07-25

Breaking · you name the settlement network when buying stablecoin

POST /v1/treasury/conversion-quotes now requires settlementNetwork when sourceAsset is "AUD". Wayex no longer selects a chain for that direction. The network you name is the chain the purchased stablecoin is delivered onto, so it is the chain your account then holds the balance on and the chain you can withdraw it on. That is your decision, not ours, and there is no default and no fallback behind it.
Migration. Add settlementNetwork to every AUD-to-stablecoin quote request. Choose from the runtimeCapabilities entries on GET /v1/treasury, and choose a chain your account can actually withdraw on. Omitting it now fails with 400 settlement_network_required on the settlementNetwork parameter. Two refusals you should treat as “pick a different chain”, not as transient errors:
  • 400 unsupported_asset_network — the asset does not settle on that chain, or Wayex cannot receive it there. This is now checked before your account’s enabled pairs, so an unwired chain fails here rather than with 422 asset_network_unavailable. A pair that is wired but not enabled for your account still returns the 422.
  • 409 conversion_route_conflict — Wayex has a settlement route pinned for that asset and you named a different chain. This check is unchanged, but it is now reachable on every AUD-to-stablecoin quote, because previously nobody sent the field. If a route is pinned for your account, name exactly that chain.
Not affected: stablecoin to AUD. That direction is unchanged. settlementNetwork stays optional there, Wayex still routes from the chains your account holds the balance on, and a supplied value is still only an override. Do not make the field mandatory across both directions in your client. See Choosing the settlement network.

Breaking · free-form maps reject a reserved key

metadata on customers and counterparties, and partyContext, businessIdentity, and glMapping on Treasury requests, now refuse the reserved key @@wxtype and any @@wxtype.esc… variant, with 400 invalid_request. Nothing is written, including on a PATCH that would otherwise merge. These keys were previously accepted. Migration. Only integrations that happen to use that exact key name are affected. Near misses such as wxtype, @@wxtypes, and my@@wxtype remain ordinary keys. See Reserved metadata key.

New hold reason · withdrawal_network_not_held

A stablecoin withdrawal on a network your account has no credited deposit and no settled conversion for is now accepted as held with statusReason withdrawal_network_not_held, instead of proceeding. The source debit is reserved and nothing is sent until Wayex releases it. Retrying will not clear it: withdraw on a network you have funded, or convert onto that network first. The withdrawal preview does not test this restriction, so an unheld network previews cleanly with canProceed true and is held on create — treat the create response as authoritative. See Withdrawals on a network you do not hold.