PAY BY BANK

Five vendors. Three requests.

Identity, open banking, balance check, fraud scoring, and multi-rail payment. Three API calls replace your entire stack.

IDENTITY
P Persona A Alloy S Socure
OPEN BANKING
P Plaid M MX F Finicity
PAYMENTS
S Stripe D Dwolla M ModTrsy
FRAUD
S Sardine U Unit21 S Sift
SPONSOR BANK
E Evolve C Column L Lead
01
customers.create
verified 318ms
02
bridge.link
pk_2b7c active 89ms
03
charges.create
$4,250 paid 203ms
THREE REQUESTS

The payments stack, collapsed

Most teams stitch together a KYC provider, an open banking aggregator, a payment processor, and a fraud vendor. Each with its own contract, SDK, and failure modes.

01

Verify the customer

One call to customers.create runs graph-based KYC, fraud scoring, watchlist screening, and address verification. Sub-second. No selfies. No third-party redirect.

Replaces Persona, Alloy, Socure for bank payment KYC
@straddle/sdk
const customer = await client.customers.create({ device: { ip_address: '192.168.1.1' }, email: 'ron.swanson@pawnee.com', name: 'Ron Swanson', phone: '+12128675309', type: 'individual', }) console.log(customer.data) // => { id: "cus_8f3a", status: "verified" }
customer = client.customers.create( device={"ip_address": "192.168.1.1"}, email="ron.swanson@pawnee.com", name="Ron Swanson", phone="+12128675309", type="individual", ) print(customer.data) # => { id: "cus_8f3a", status: "verified" }
curl -X POST https://api.straddle.com/v1/customers \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "name": "Ron Swanson", "email": "ron.swanson@pawnee.com", "phone": "+12128675309", "type": "individual", "device": { "ip_address": "192.168.1.1" } }'
02

Connect the account

Initialize a Bridge widget session and let your customer connect their bank. The widget handles auth, account selection, and verification. You get back a Paykey: a secure token binding identity to account.

Replaces Standalone Plaid, MX, Finicity integrations
@straddle/sdk
// Generate a session token for the Bridge widget const session = await client.bridge.initialize({ customer_id: 'cus_8f3a', }) // Pass bridge_token to your frontend // The widget handles bank selection and verification // => { bridge_token: "br_tok_..." } // Or bridge an existing Plaid token const paykey = await client.bridge.link.plaid({ customer_id: 'cus_8f3a', plaid_token: 'processor-sandbox-...', }) // => { paykey: "pk_2b7c", status: "active", label: "Chase ****4821" }
# Generate a session token for the Bridge widget session = client.bridge.initialize( customer_id="cus_8f3a", ) # Pass bridge_token to your frontend # The widget handles bank selection and verification # => { bridge_token: "br_tok_..." } # Or bridge an existing Plaid token paykey = client.bridge.link.plaid( customer_id="cus_8f3a", plaid_token="processor-sandbox-...", ) # => { paykey: "pk_2b7c", status: "active", label: "Chase ****4821" }
# Initialize Bridge widget session curl -X POST https://api.straddle.com/v1/bridge/initialize \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_8f3a" }' # Or bridge a Plaid token directly curl -X POST https://api.straddle.com/v1/bridge/plaid \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_8f3a", "plaid_token": "processor-sandbox-..." }'
03

Move the money

charges.create checks balance, selects the optimal rail, initiates the transfer, and monitors for fraud. You set the intent; the system picks the fastest path.

Replaces Stripe ACH, Dwolla, Modern Treasury for bank payments
@straddle/sdk
const charge = await client.charges.create({ amount: 425000, config: { balance_check: 'required' }, consent_type: 'internet', currency: 'usd', description: 'Monthly subscription', device: { ip_address: '192.168.1.1' }, external_id: 'inv_1042', paykey: 'pk_2b7c', payment_date: '2026-04-12', }) console.log(charge.data) // => { id: "ch_9d4e", status: "created", rail: "same_day_ach" }
from datetime import date charge = client.charges.create( amount=425000, config={"balance_check": "required"}, consent_type="internet", currency="usd", description="Monthly subscription", device={"ip_address": "192.168.1.1"}, external_id="inv_1042", paykey="pk_2b7c", payment_date=date.fromisoformat("2026-04-12"), ) print(charge.data) # => { id: "ch_9d4e", status: "created", rail: "same_day_ach" }
curl -X POST https://api.straddle.com/v1/charges \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "amount": 425000, "paykey": "pk_2b7c", "currency": "usd", "consent_type": "internet", "description": "Monthly subscription", "payment_date": "2026-04-12", "config": { "balance_check": "required" }, "device": { "ip_address": "192.168.1.1" }, "external_id": "inv_1042" }'
MULTI-RAIL ROUTING

The system picks the fastest path

You set the payment intent. Straddle evaluates amount, urgency, and recipient bank to select the optimal rail. No configuration needed.

RAIL SPEED
ACH 1 business day
Same-Day ACH same day
RTP seconds
FedNow coming soon
AFTER THE REQUEST

The system handles the rest

Signed webhooks for every state change. ML fraud scoring on every transaction. Balance monitoring, sanctions screening, velocity checks. You get notified; you don't have to poll.

EVENT STREAM
live
charge.created ch_9d4e
charge.scheduled ch_9d4e
charge.pending originated to ACH
charge.clearing clearing through bank
charge.completed paid

Your first charge in three requests

$ straddle customers create --name 'Ron Swanson' $ straddle bridge link --customer cus_8f3a $ straddle charges create --amount 425000 --paykey pk_2b7c

Get sandbox access in minutes. No sales calls, no contracts. Build first, talk to us when you're ready.

Get API keys Talk to sales