What are payment rails?

A payment rail is the underlying network or system used to move money from one party to another. Each rail has its own settlement speed, geographic coverage, currency support, and fee structure. The OpenFX MVP supports 5 payment rails, giving you flexibility to choose the best rail for each payment based on speed, cost, and destination. Every payment on OpenFX travels over exactly one rail. You can either specify the rail explicitly using rail-specific endpoints (POST /payments/{rail}) or let the unified POST /payments endpoint handle routing based on the payment parameters.

Supported rails

RailNameCoverageSpeedCurrenciesBest for
achACHUS domestic1-3 business days (standard), same-day availableUSDPayroll, vendor payments, recurring transfers
fedwireFedwireUS domesticSame-day (irrevocable)USDUrgent large-value transfers
swiftSWIFTInternational (180+ countries)1-5 business daysMulti-currencyCross-border payments to any country
cryptoCryptoGlobalMinutes (varies by chain)USDC, USDT, EURC, PYUSDStablecoin transfers, crypto on/off-ramp
openOPENOpenFX internalInstantSame-currencyIntercompany transfers, platform marketplace

Rails discovery

Before sending a payment, you can programmatically discover which rails are available, what currencies and countries they support, and what fields are required. This is especially useful for building dynamic UIs or validating payment parameters before submission.

List available rails

curl -X GET https://sandbox.api.openfx.com/v1/rails \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP"
You can filter rails by currency or country:
# Rails that support EUR
curl -X GET "https://sandbox.api.openfx.com/v1/rails?currency=EUR" \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP"

# Rails available in the UK
curl -X GET "https://sandbox.api.openfx.com/v1/rails?country=GB" \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP"

Get rail details

Retrieve detailed information about a specific rail, including capabilities, cutoff times, and required fields.
curl -X GET https://sandbox.api.openfx.com/v1/rails/ach \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP"
The response includes:
FieldDescription
idRail identifier (ach, fedwire, swift, crypto, open)
nameHuman-readable name
statusactive, limited, or maintenance
supportedCurrenciesArray of ISO 4217 currency codes
supportedCountriesArray of ISO 3166-1 country codes
typicalSettlementTimeHuman-readable settlement time
cutoffTimeDaily cutoff time in UTC (null for instant rails)
capabilitiesArray: inbound, outbound, instant, cop, vop, return, same_day
requiredFieldsField names required for payment creation on this rail

Pre-flight validation

Before creating a payment, you can validate the payment fields against a specific rail without actually creating a payment resource. This catches errors like invalid routing numbers, unsupported currencies, or missing required fields early in the flow.
curl -X POST https://sandbox.api.openfx.com/v1/rails/ach/validate \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceAccountId": "acc_01953e1a5f4b7002",
    "paymentMethodId": "pm_01953e1a5f4b7300",
    "amount": {
      "currency": "USD", "value": "500000"
    },
    "achType": "same_day"
  }'
A successful validation returns 200 with valid: true. A failed validation returns 422 with field-level errors:
{
  "valid": false,
  "rail": "ach",
  "fieldErrors": [
    {
      "field": "routingNumber",
      "code": "invalid_format",
      "message": "Routing number must be exactly 9 digits."
    },
    {
      "field": "amount.value",
      "code": "out_of_range",
      "message": "Amount exceeds the maximum for ACH same-day ($1,000,000)."
    }
  ]
}
Use pre-flight validation to build form validation in your UI. Call POST /rails/{rail}/validate as the user fills out payment details, and display field-level errors before they submit.

Unified vs. rail-specific endpoints

OpenFX provides two ways to create payments:

Unified endpoint (POST /payments)

The unified endpoint accepts any rail via the rail field in the request body. It uses discriminator-based polymorphism to route to the correct rail handler. Use this when you want a single integration point for all rails.
curl -X POST https://sandbox.api.openfx.com/v1/payments \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "sourceAccountId": "acc_01953e1a5f4b7002",
    "counterpartyId": "cpt_01953e1a5f4b7004",
    "paymentMethodId": "pm_01953e1a5f4b7300",
    "rail": "ach",
    "sendAmount": { "currency": "USD", "value": "150000" },
    "reference": "Invoice #INV-2026-0042"
  }'

Rail-specific endpoints (POST /payments/{rail})

Rail-specific endpoints provide simpler, rail-native request schemas without the rail discriminator field. Each rail has its own set of fields tailored to that network.
curl -X POST https://sandbox.api.openfx.com/v1/payments/ach \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "sourceAccountId": "acc_01953e1a5f4b7002",
    "paymentMethodId": "pm_01953e1a5f4b7300",
    "amount": { "currency": "USD", "value": "150000" },
    "achType": "standard",
    "secCode": "CCD",
    "reference": "Invoice #INV-2026-0042"
  }'
Both approaches create the same Payment resource with a pmt_ prefixed ID. The rail-specific endpoints are a convenience — they do not create a different resource type.

When to use which

ApproachBest for
Unified POST /paymentsMulti-rail applications where rail selection is dynamic. Single code path for all payment types.
Rail-specific POST /payments/{rail}Applications focused on a specific rail. Simpler request schemas with rail-native fields. Better code completion in typed SDKs.

Next steps

API reference