Guidelines and troubleshooting
Our FX payment APIs enable your integration to support international transactions through two core workflows: settling supplier invoices in foreign currencies and initiating direct transfers to global counterparties. These workflows are presented as API recipes that define the required endpoints, request payloads, and validation rules needed to execute each operation.
To support you in your API integration, the sections below include shared guidelines and troubleshooting steps that apply to both workflows.
Use these matrices and checklists during your integration phase to correctly handle API edge cases and avoid validation failures.
Beneficiary address fields
Address fields are requested conditionally based on beneficiary country, account scheme, and bank account country.
Backend validation returns FAILED_CONTEXT_VALIDATION errors naming specific missing fields.
| Field | API path | Required when |
|---|---|---|
| Country Code | address.countryCode | Always |
| Street Name | address.streetName | Required conditionally |
| Building Number | address.buildingNumber | Required conditionally |
| Post Box | address.postBox | Required conditionally |
| Postal Code | address.postalCode | Required conditionally |
| City | address.city | Required conditionally |
| State | address.state | Required conditionally |
Pattern: Attempt validation → if FAILED_CONTEXT_VALIDATION with a field name → show that field as required → re-validate. Surface RESTRICTED_ZONE immediately without showing address fields.
Error handling
| HTTP | Scenario | Action |
|---|---|---|
| 400 | Invalid beneficiary fields, reference too long, fee expired | Re-validate; resubmit with fresh fee |
| 401 | Token expired or invalid scope | Refresh token |
| 403 | Missing Origin/User-Agent headers or insufficient scope | Add headers; confirm token scope |
| 422 | creditorVerificationId is a TECH_ERROR id ("btxErrId...") | Omit creditorVerificationId from execute when VOP = TECH_ERROR |
Key constraints
| Constraint | Detail |
|---|---|
| Payer currency | EUR only - payer account must be EUR-denominated |
| FX market hours | Mon 00:00 – Fri 21:30 GMT |
| Fee expiration | Fees expire (~2 min in UAT) - show countdown timer from expirationTime; re-fetch on expiry |
| agreementPolicy | CONSENT_REQUIRED - user must explicitly accept the fee quote before validate/execute |
| acceptedFeeId | Must be the same across validate and execute; re-validate if fee is refreshed |
| creditorVerificationId | Include only when VOP returns "VOP-..." id; omit when result = TECH_ERROR |
| Reference length | 1–140 characters, regex ^.{1,140}$ |
Common pitfalls
- Fee expiration: Fees expire in minutes. Skip the countdown timer and users get
FEE_MISMATCH_OR_EXPIREDon execute. - Not re-validating after fee acceptance: After user accepts fee, re-call validate with
acceptedFeeIdbefore executing. - Mismatched acceptedFeeId: The id used in validate and execute must be the same. If the fee expires between the two calls, re-fetch and re-validate first.
- Passing VOP TECH_ERROR id: When VOP returns
result = "TECH_ERROR", the id starts withbtxErrId. Do NOT pass this ascreditorVerificationId- the execute will return 422. Omit the field entirely. - Restricted zone not handled separately:
RESTRICTED_ZONEis a sub-code ofFAILED_CONTEXT_VALIDATION. Block immediately - do not show address form. - Wrong validate endpoint by flow type: Documents use
/solution/business/v2/.../documents:validate; transfers use/payments/v2/.../context:validate. These are different endpoints with different request/response shapes.