Settlement Rails
A rail is the physical mechanism that moves capital from payer to payee once a chio receipt is final. The kernel does not pick rails on its own: the operator binds each capability to one of seven variants from CapitalExecutionRailKind in chio-credit, and the runtime then dispatches the matching adapter when execution completes.
Use this page when
PaymentAdapter trait. Don't use this if you want on-chain escrow internals (see On-Chain Settlement) or the cycle that closes pending settlements (see Reconciliation).The Seven Rails
The enum is defined in chio-credit/src/credit/capital_and_execution.rs and re-exported through chio-core. Every CapitalExecutionRail artifact picks exactly one variant, plus a rail_id, a custody provider, and optional source/destination account references.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum CapitalExecutionRailKind {
Manual,
Api,
Ach,
Wire,
Ledger,
Sandbox,
Web3,
}Manual
Human-initiated movement outside the system. The operator records the receipt, ships an invoice, and reconciles when the customer pays by check, ACH credit, or however else they like. Chio still owns the truth: the receipt is signed and counted, but the actual transfer is an out-of-band action.
- Latency. Days to weeks. Bound by accounts-receivable cadence.
- Finality. Recorded on operator confirmation. No automatic dispute window.
- Cost profile. Lowest variable cost; highest staff cost.
- Use when. Counterparty is a billed enterprise, the relationship predates chio, or the legal contract requires invoice settlement.
Api
Payment processor integrations: Stripe, Adyen, Braintree, Worldpay, and any other off-chain rail with a synchronous authorize/capture API. Settlement runs through the PaymentAdapter trait in chio-kernel/src/payment.rs (covered below).
- Latency. Seconds for authorize and capture; one to three business days for funds availability.
- Finality. Provisional on capture; final after the processor's chargeback window closes.
- Cost profile. Per-transaction fees plus interchange; higher than ACH or Wire on average ticket.
- Use when. Retail-style flows, card payments, or any rail whose API maps onto authorize/capture/release/refund.
Ach
Bank-to-bank ACH transfers. Batched, slower, and substantially cheaper per transaction than card rails. The chio runtime treats ACH as an async rail: a settlement intent is recorded, the operator triggers the ACH file, and the rail eventually returns a settled-or-failed signal.
- Latency. One to three business days; same-day ACH available on some rails.
- Finality. Settled on bank confirmation; reversible during the NACHA return window (up to 60 days for consumer disputes).
- Cost profile. Cents per transfer; flat fee regardless of amount.
- Use when. Large operators settling on a monthly or weekly cadence, or any flow where unit economics make card processing untenable.
Wire
Wire transfers. Same-day domestic, T+1 international, irrevocable on the receiving bank's confirmation.
- Latency. Hours; same-day for FedWire and SWIFT GPI.
- Finality. Final on receipt. No automatic recall.
- Cost profile. Tens of dollars per wire on each end; international wires add FX spread.
- Use when. High-value, low-volume settlement where same-day finality matters more than per-transaction cost.
Ledger
Internal ledger entries inside a single operator's book. No external capital movement. The receipt records that one subaccount debited and another credited; bank balances do not change. Useful for cost allocation between teams or for transfers between business units that share a treasury.
- Latency. Synchronous; the entry posts as the receipt is signed.
- Finality. Immediate within the operator's book.
- Cost profile. Effectively zero per transaction.
- Use when. Internal chargebacks, departmental cost allocation, or any flow that never crosses an external boundary.
Sandbox
The development and test rail. Settlement is recorded in the receipt log with a synthetic reference; no real capital moves anywhere. Useful for end-to-end integration tests against the same primitives as production without any blast radius.
- Latency. Synchronous and configurable.
- Finality. Synthetic; the rail returns whatever lifecycle the test fixture asks for.
- Cost profile. Zero.
- Use when. CI, devnet bring-up, contract qualification, or any flow that should not touch real money.
Web3
On-chain settlement through the ChioEscrow family of contracts. The kernel writes a signed dispatch artifact, the chain locks funds, and a release transaction (dual-signature or merkle proof) settles the escrow against the receipt root. Full coverage is on the On-Chain Settlement page.
- Latency. Sub-second authorize, seconds-to-minutes finality depending on chain.
- Finality. Probabilistic and explicit. Captured by
SettlementFinalityStatus(AwaitingConfirmations, AwaitingDisputeWindow, Finalized, Reorged). - Cost profile. Gas plus token-transfer cost. Cheaper than wire on small amounts; chain choice matters.
- Use when. Counterparty is a smart contract, an autonomous agent, or any actor for whom an on-chain receipt is the canonical record.
PaymentAdapter Lifecycle
For off-chain rails (Api, Ach, Wire) the kernel speaks to each rail through the PaymentAdapter trait. The contract is a four-step lifecycle: pre-authorize a ceiling, run the tool, then capture or release the actual amount, with refund as a post-settlement reversal.
pub trait PaymentAdapter: Send + Sync {
/// Authorize or prepay up to `amount_units` before the tool executes.
fn authorize(
&self,
request: &PaymentAuthorizeRequest,
) -> Result<PaymentAuthorization, PaymentError>;
/// Finalize payment for the actual cost after tool execution.
fn capture(
&self,
authorization_id: &str,
amount_units: u64,
currency: &str,
reference: &str,
) -> Result<PaymentResult, PaymentError>;
/// Release an unused authorization hold.
fn release(
&self,
authorization_id: &str,
reference: &str,
) -> Result<PaymentResult, PaymentError>;
/// Refund a previously executed payment.
fn refund(
&self,
transaction_id: &str,
amount_units: u64,
currency: &str,
reference: &str,
) -> Result<PaymentResult, PaymentError>;
}Each rail's richer settlement state is reported back through RailSettlementStatus (Authorized, Captured, Settled, Pending, Failed, Released, Refunded) and folds into the canonical SettlementStatus the receipt carries (NotApplicable, Pending, Settled, Failed). The mapping is intentionally lossy: the receipt cares about whether the money is moving, has moved, or has stopped moving; the rail can carry whatever intermediate detail it likes in metadata.
Authorize, Dispatch, Capture
The flow that consumes this trait inside the kernel is:
- Pre-authorize.
authorize()reserves up to the quoted amount on the underlying rail. The returnedPaymentAuthorizationholds the rail's authorization id and a settled flag. Ifsettled = true(e.g. an x402 prepaid response), the authorization already covers the full quoted cost. - Dispatch the tool. The governed call runs. The chio kernel observes the actual cost via metering and produces a final amount.
- Capture or release. If the observed cost is positive,
capture()finalizes the authorization at the actual amount. If the observed cost is zero (denial, no-op, error),release()unlocks the hold cleanly. Any later reversal goes throughrefund().
Two adapters ship in chio-kernel out of the box: X402PaymentAdapter for per-request stablecoin payments and AcpPaymentAdapter for shared-payment-token holds (Agentic Commerce Protocol). Both treat capture/release/refund after the initial authorize as bookkeeping rather than additional remote round-trips, which keeps the bridge narrow while still exercising one real authorization hop.
Settlement Modes
Independently of which rail moves the money, every metered call picks one of three settlement postures. The enum lives in chio-core-types/src/capability.rs and rides on the receipt as MeteredSettlementMode:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MeteredSettlementMode {
/// The action should not execute unless the quoted amount is prepaid.
MustPrepay,
/// The action may execute against a hold and settle later
/// via capture/release.
HoldCapture,
/// The action may execute first and settle later with truthful
/// pending state.
AllowThenSettle,
}| Mode | Pre-execution | Post-execution | Failure mode |
|---|---|---|---|
must_prepay | Quoted amount captured up front | Refund delta if observed cost lower | Deny on insufficient funds |
hold_capture | Quoted amount authorized as a hold | Capture observed amount; release remainder | Hold expires; release returns funds |
allow_then_settle | No financial commitment taken | Authorize + capture observed amount after | Receipt records pending then failed |
The mode is chosen on the capability or governed intent. A zero-trust public agent is best with must_prepay; a known high-volume integration partner can run on hold_capture; an internal team rail wired through Ledger may opt for allow_then_settle because the counterparty is your own treasury.
Choosing a Rail
Three axes drive the choice: latency, cost, and counterparty trust. The matrix below maps the seven rails onto those axes; in practice operators run a portfolio (multiple rails enabled at once, picked per-capability or per-counterparty).
| Rail | Latency | Per-tx cost | Trust requirement | Reversibility |
|---|---|---|---|---|
Manual | Days to weeks | Low (high staff cost) | High (relationship-based) | Manual |
Api | Seconds to days | Medium-high | Low (processor-mediated) | Chargeback window |
Ach | 1 to 3 days | Cents per transfer | Medium (bank-mediated) | NACHA return window |
Wire | Same-day | $15 to $50 each leg | Low (bank-mediated) | None (irrevocable) |
Ledger | Synchronous | ~0 | Single operator | Reversal entry |
Sandbox | Configurable | 0 | N/A (test only) | N/A |
Web3 | Seconds to minutes | Gas + token transfer | Trust-minimized (escrow + bond) | Refund / merkle dispute |
Rail and mode are orthogonal
Api rail can run in any of the three modes. A Web3 escrow defaults to hold_capture because the contract literally locks funds during execution, but that is convention, not a constraint of the enum.Worked Example: Two-Rail Operator
A tool platform serves both casual API users (low-trust, high-volume, small ticket) and a small set of large enterprise operators (high-trust, low-volume, large ticket). The right move is to enable two rails and bind them per-counterparty.
Api Rail for Retail Flow
For the casual users, configure an Api rail backed by Stripe. Capabilities for these agents bind settlement_mode = must_prepay so the kernel forces a real Stripe authorization before any tool runs:
use chio_core::credit::{
CapitalExecutionRail, CapitalExecutionRailKind,
};
let retail_rail = CapitalExecutionRail {
kind: CapitalExecutionRailKind::Api,
rail_id: "stripe-prod-us".to_string(),
custody_provider_id: "stripe.com".to_string(),
source_account_ref: Some("payer:agent-card".to_string()),
destination_account_ref: Some("acct:platform-revenue".to_string()),
jurisdiction: Some("US".to_string()),
};The Stripe adapter implements PaymentAdapter against the Stripe SDK: authorize creates a PaymentIntent with capture_method=manual; capture calls capture() on the intent; release calls cancel(); refund creates a Refund. The same trait covers card payments, bank-debit through Stripe ACH, and direct transfers.
Ach Rail for Monthly Settlement
For the enterprise operators, configure an Ach rail and bind their capabilities to settlement_mode = allow_then_settle. Each tool call accrues against an open exposure on the operator's account; the rail dispatches a single ACH file at month close to settle the cumulative balance.
let enterprise_rail = CapitalExecutionRail {
kind: CapitalExecutionRailKind::Ach,
rail_id: "ach-batch-monthly".to_string(),
custody_provider_id: "treasury-bank.example".to_string(),
source_account_ref: Some("acct:operator-acme".to_string()),
destination_account_ref: Some("acct:platform-collections".to_string()),
jurisdiction: Some("US".to_string()),
};At month close, the platform aggregates all reconciled receipts where the rail kind is Ach and the rail id matches, computes a single net amount per operator, and ships one ACH debit per operator. The receipts already carry the truth; the ACH file just moves the money.
Reversibility cost
Configuration Shape
The rail attaches to a capital execution instruction. The full artifact has 14 fields; the rail itself is six:
pub struct CapitalExecutionRail {
pub kind: CapitalExecutionRailKind,
pub rail_id: String,
pub custody_provider_id: String,
pub source_account_ref: Option<String>,
pub destination_account_ref: Option<String>,
pub jurisdiction: Option<String>,
}rail_id must be stable across an operator's deployment because reconciliation joins on it. custody_provider_id names the entity holding the funds in flight (Stripe, the operator treasury bank, the on-chain escrow contract). The optional account refs are useful when one rail aggregates multiple sources or destinations; the jurisdiction hint is consumed by compliance policy when an operator scopes rails to specific legal regions.
What Each Receipt Records
Whichever rail moves the money, the receipt records the same canonical fields:
payment_reference: stable rail-side identifier (Stripe charge id, ACH trace number, on-chain tx hash) for downstream reconciliation.settlement_status: one of NotApplicable, Pending, Settled, Failed.metered_billing: the quoted units, observed units, andMeteredSettlementMode.- The
CapitalExecutionRailartifact itself, when an instruction has been emitted.
The reconciliation cycle (covered on the Reconciliation & Watchdog page) reads these fields, joins against the rail's native notifications, and flips status from Pending to Settled or Failed.
See Also
- On-Chain Settlement covers the Web3 rail in depth.
- Reconciliation & Watchdog covers the cycle that closes out each rail's pending settlements.
- Tool Pricing covers how quoted cost is computed before the rail ever sees the authorization.
- Settlement guide is a hands-on walkthrough of wiring a rail end-to-end.
- x402 and Chainlink are integration-level views of the prepaid HTTP and cross-chain rails.