Skip to main content

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.

FieldAPI pathRequired when
Country Codeaddress.countryCodeAlways
Street Nameaddress.streetNameRequired conditionally
Building Numberaddress.buildingNumberRequired conditionally
Post Boxaddress.postBoxRequired conditionally
Postal Codeaddress.postalCodeRequired conditionally
Cityaddress.cityRequired conditionally
Stateaddress.stateRequired 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

HTTPScenarioAction
400Invalid beneficiary fields, reference too long, fee expiredRe-validate; resubmit with fresh fee
401Token expired or invalid scopeRefresh token
403Missing Origin/User-Agent headers or insufficient scopeAdd headers; confirm token scope
422creditorVerificationId is a TECH_ERROR id ("btxErrId...")Omit creditorVerificationId from execute when VOP = TECH_ERROR

Key constraints

ConstraintDetail
Payer currencyEUR only - payer account must be EUR-denominated
FX market hoursMon 00:00 – Fri 21:30 GMT
Fee expirationFees expire (~2 min in UAT) - show countdown timer from expirationTime; re-fetch on expiry
agreementPolicyCONSENT_REQUIRED - user must explicitly accept the fee quote before validate/execute
acceptedFeeIdMust be the same across validate and execute; re-validate if fee is refreshed
creditorVerificationIdInclude only when VOP returns "VOP-..." id; omit when result = TECH_ERROR
Reference length1–140 characters, regex ^.{1,140}$

Common pitfalls

  • Fee expiration: Fees expire in minutes. Skip the countdown timer and users get FEE_MISMATCH_OR_EXPIRED on execute.
  • Not re-validating after fee acceptance: After user accepts fee, re-call validate with acceptedFeeId before 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 with btxErrId. Do NOT pass this as creditorVerificationId - the execute will return 422. Omit the field entirely.
  • Restricted zone not handled separately: RESTRICTED_ZONE is a sub-code of FAILED_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.