MVP API (v0.1) — The payments surface covers core payment creation, lifecycle tracking, and cross-currency delivery. Additional capabilities (staged intents, compliance gates, refunds, batches) will be added in future releases.

Why payments matter

Payments unlock the majority of OpenFX’s revenue potential. FX-only captures a fraction of transaction economics — customers who hold balances, receive inbound payments, and originate outbound payments generate 3-5x the revenue per customer through account fees, payment fees, and FX on a larger transaction base. The payments layer also enables the local rail advantage: instead of routing a cross-border payment via SWIFT ($25-45, 2-5 business days), OpenFX can convert currencies via the FX Engine and deliver via local rails. For example, convert USD to GBP and deliver via UK Faster Payments — instant delivery, under 1 GBP in fees. This is only possible because OpenFX combines FX conversion and multi-rail payment origination in a single platform.

What Are Payments?

Payments are Layer 3 of the OpenFX platform — the top of the stack. A payment moves money from an OpenFX account to an external counterparty via a specific payment rail. Every payment touches the layers below it:
  • Layer 0 (Identity): The customer who owns the source account must be onboarded and KYB-approved.
  • Layer 1 (FX Engine): If the payment involves a currency conversion, the FX engine provides the quote and executes the conversion.
  • Layer 2 (Banking): The source account holds the funds that are debited to fund the payment.
  • Layer 3 (Payments): The payment is originated on the chosen rail and delivered to the counterparty.
Your Account (Layer 2)
  |
  |-- FX Conversion if needed (Layer 1)
  |
  +-- Payment originated on rail --> Counterparty receives funds
        ACH / Fedwire / SWIFT / Crypto / OPEN

Two Approaches to Creating Payments

OpenFX provides two ways to create a payment. Both produce the same Payment resource with the same lifecycle.

Unified endpoint

POST /payments accepts any rail. You specify the rail field in the request body, and the API routes to the appropriate backend. This is the canonical entrypoint for cross-rail payment creation.
{
  "sourceAccountId": "acc_01953e1a5f4b7002",
  "counterpartyId": "cpt_01953e1a5f4b7004",
  "paymentMethodId": "pm_01953e1a5f4b7300",
  "rail": "swift",
  "sendAmount": { "currency": "USD", "value": "1000000" },
  "purpose": "invoice_payment"
}

Rail-specific endpoints

POST /payments/{rail} (e.g., POST /payments/ach, POST /payments/swift) provides direct access to a specific rail with rail-native request and response schemas. The request body omits the rail field since it is implicit in the URL.
// POST /payments/ach
{
  "sourceAccountId": "acc_01953e1a5f4b7002",
  "counterpartyId": "cpt_01953e1a5f4b7004",
  "paymentMethodId": "pm_01953e1a5f4b7300",
  "sendAmount": { "currency": "USD", "value": "150000" }
}
Use the unified endpoint when your integration handles multiple rails dynamically. Use rail-specific endpoints when you always send on a single rail and want the tightest request/response schemas with rail-native fields.

Supported Payment Rails

RailEndpoint SuffixCurrenciesTypical SettlementUse Case
ach/payments/achUSD1-2 business daysUS domestic payments
fedwire/payments/fedwireUSDSame dayUS domestic high-value
swift/payments/swiftMulti-currency1-5 business daysInternational cross-border
crypto/payments/cryptoStablecoinsMinutesOn-chain stablecoin delivery
open/payments/openAny supportedInstantFee-free internal platform payments

Payment Lifecycle at a Glance

Every payment progresses through a defined set of statuses. Most payments follow the happy path: created -> processing -> completed. See Payment Lifecycle for detailed status definitions and webhook events for each transition.

Key Payment Fields

FieldTypeDescription
idstringPayment ID with pmt_ prefix (e.g., pmt_01953e1a5f4b7005)
sourceAccountIdstringThe account debited to fund the payment
counterpartyIdstringThe recipient of the payment
paymentMethodIdstringThe counterparty’s delivery method (rail-specific details)
railenumOne of: ach, fedwire, swift, crypto, open
statusenumCurrent lifecycle status
sendAmountMoneyAmount sent from source ({ "currency": "USD", "value": "150000" })
receiveAmountMoneyAmount received by counterparty (may differ if cross-currency)
amountInputSideenumWhether you specified send or receive amount
feesFeeBreakdownFee details including feeAmount, feeCurrency, and feeComponents
totalDebitAmountMoneyTotal debited from source account (send amount + fees)
exchangeRateExchangeRateDetailFX rate details if cross-currency
executionPreferenceenumuse_quote (locked rate) or at_market (spot rate)
senderReferencestringYour reference for the payment (visible to counterparty on some rails)
purposeenumPayment purpose code (required for SWIFT)
createdAtdatetimeISO 8601 timestamp

Guides in This Section

API Reference