API version 2026-10-08

One API for every payment rail.

Unirail sits between your platform and the providers that move money. Integrate once to link accounts, price the routes between them, let your user choose, and pay along legs, while every provider’s webhooks arrive as one event stream.

The GDS for payments: providers plug in once, and your platform routes each payment through whichever one fits it.

PlaidYapilyEnable BankingTrueLayerAirwallexUnirailYour appquotes · legs · events
integrated listed, not connectable yet
How it works

Integrate once. Route every payment.

Your backend talks to Unirail with one secret key. Unirail talks to Plaid, Yapily and Enable Banking today, and to each provider that gets an adapter after them.

  1. 01

    Connect providers from your vault

    Add a connection per provider and environment in the dashboard. Unirail reads its credentials from your Infisical through OIDC federation, read-only on one folder.

    /unirail/plaid/SECRET
  2. 02

    Call one API

    Customers, bank links, accounts as payto:// addresses, quotes and payment intents have the same shape whichever provider moves the money.

    POST /v1/route_quotes
  3. 03

    Let your user pick the route

    Quotes come back labelled Cheapest, Fastest or Recommended, each with its legs, cost, ETA and custody. Routes that can’t work come back with the reason.

    label: "fastest"
  4. 04

    Listen to one event stream

    Provider webhooks, polling and status deadlines become Unirail events, signed as Standard Webhooks and replayable from /v1/events.

    payment_intent.succeeded
Credentials

Your provider credentials never leave your vault.

Plaid secrets, Yapily application secrets and Enable Banking keys stay in your Infisical. Unirail is granted read access to one folder through OIDC federation and never stores what it reads.

  • Your machine identity trusts Unirail’s OIDC issuer. There is no client secret or vault token for anyone to leak.
  • Read-only on one folder, bound per Unirail environment, so sandbox and production credentials stay apart.
  • Values live in isolate memory for at most five minutes and are never written to Unirail’s database, logs or traces.
  • Revoke Unirail by deleting one identity in Infisical.
Connect Infisical with OIDC →
Your Infisical · project payments · env prod
# folder layout Unirail reads
/unirail/plaid/CLIENT_ID
/unirail/plaid/SECRET
/unirail/yapily/APPLICATION_ID
/unirail/yapily/APPLICATION_SECRET

# machine identity “unirail”
auth      OIDC
issuer    https://api.unirail.dev/oidc
subject   org:<orgId>:env:<envId>
access    read-only · /unirail · prod
Routing

Every payment gets a route, or a reason.

Ask for quotes between two accounts and Unirail checks every connected provider against schemes, amounts, currencies and your routing policy. You get up to three labelled routes and a plain explanation for the rest.

Legs
Each route is one or more legs, each naming its rail, amount and who holds the money after it.
Cost and ETA
What the payer pays, the fee breakdown and who pays each line, with p50 and p90 timings.
Custody
Today’s routes run bank to bank with no one holding funds. Meta-providers such as Airwallex hold money in transit, so they only appear where your policy admits it.
Approval
Bind your user’s approval to the quote’s id and digest. If anything they approved changes, the payment is refused.
POST /v1/route_quotesIllustrative values
£50.00 · GBP
Payer’s bank •••• 4321 → payee •••• 0008
leg 0custodyAfter
payerplaidpayee
none
Payer pays
£0.00
£0.20 provider fee, paid by platform
ETA p50
12 s
p90 2 min
Likelihood
98%
of success
Firmness
firm
expires in 5 min
id qt_7Hd2kQm4Rxdigest 9f2c4be1…a71e
infeasible · 1
airwallex

Two legs through the provider’s collection account hold money in transit (provider-transit). This environment’s routing policy admits custody none only.

Developers

A typed SDK for your backend.

@unirail/sdk is built on the same contract the API serves, so every request and response is typed. It runs anywhere with fetch and WebCrypto: Workers, Node, Bun and Deno.

  • Secret keys are server-side only; the key’s environment decides where each call runs.
  • Every write takes an idempotency key you derive from your own record, so retries are safe.
  • The SDK pins API version 2026-10-08, sent as Unirail-Version on every request.
import { createUnirail } from "@unirail/sdk";

const unirail = createUnirail({ apiKey: process.env.UNIRAIL_SECRET_KEY! });

// Price every route between two accounts
const { quotes, infeasible } = await unirail.routeQuotes.create({
  from: payer.unirailAccountId,
  to: payee.unirailAccountId,
  amount: { value: "5000", asset: "iso4217:GBP" },
  preference: "recommended",
});

// Your user picks one and approves exactly that id + digest
const quote = quotes.find((q) => q.id === approval.quoteId)!;

const intent = await unirail.paymentIntents.create(
  { quote: quote.id, digest: quote.digest, returnUri },
  { context: { idempotencyKey: `payment:${payment.id}` } },
);

// Send your user to approve at their bank, then call paymentIntents.advance
if (intent.nextAction?.kind === "redirect") redirect(intent.nextAction.url);

Start in the sandbox.

Create an organisation, take a test key from the sandbox environment and connect provider sandboxes from your vault. Live keys stay separate until you’re ready.