USDC settlement
QairoPay settles eligible flows in USD Coin (USDC) on the Aptos blockchain. For tenants, this means same-day USDC liquidity, on-chain payouts, and the float economics that drive the volume-tied platform-fee discount.
For your code, settlement is a webhook event you reconcile against. You don’t usually broadcast on-chain transactions directly — QairoPay does that under a typed OnRampAdapter contract.
The flow
flowchart TD
A[Cardholder spend USD] --> B[Sponsor bank<br/>authorize and capture]
B --> C[QairoPay accrues<br/>settlement payable USD]
C --> D{Daily netting cycle<br/>T+0}
D --> E[On-ramp via Bridge<br/>USD to USDC]
E --> F[USDC delivered to<br/>tenant treasury wallet<br/>on Aptos]
F --> G[settlement.completed<br/>webhook fires]
G --> H[Your reconciler<br/>records inflow]
D -. failure .-> X[settlement.failed<br/>manual review]
classDef bridge fill:#F4ECD8,stroke:#B88A2E,color:#7A5A1B;
classDef onchain fill:#E6F1EC,stroke:#1F7A5A,color:#115540;
classDef webhook fill:#E2E6EE,stroke:#2A3A5E,color:#0F172A;
class E bridge
class F onchain
class G,X webhook On-ramp partners
Per Constitution Principle XIV, all fiat-to-USDC conversion goes through a typed OnRampAdapter. The Phase 2 implementation is BridgeOnRampAdapter, which uses Bridge (by Stripe) under the hood.
The adapter is an internal contract — you don’t call Bridge directly. You ask QairoPay to settle, QairoPay routes through Bridge, USDC lands on Aptos. If we ever swap the adapter (e.g., to a second provider for redundancy), your code doesn’t change.
1. Configure your treasury
Before settlement can run, configure where USDC should land. You can use the QairoPay-managed treasury (default — we hold USDC under qualified custody, you withdraw via the API or dashboard) or bring your own Aptos wallet.
await qp.treasury.update({ mode: "self_custodied", aptos_address: "0x4cba...",});Self-custody requires the wallet to be a QairoPay-allowlisted address — usually a multisig with signers identified in your KYB. Set this up via the dashboard once; the API just confirms it.
2. Inspect a settlement
const settlement = await qp.settlements.retrieve("set_01HZX");{ "id": "set_01HZX", "status": "completed", "currency": "USD", "amount_cents": 218043, "usdc_amount": "2180.43", "fee_cents": 2180, "net_cents": 215863, "on_ramp": { "provider": "bridge", "reference": "bridge_tx_abc123", "rate": "0.99999500" }, "on_chain": { "network": "aptos", "tx_hash": "0xa1b2...", "block_height": 234820001 }, "lines": [ { "type": "card_transaction", "txn_id": "txn_01HZX", "amount_cents": 12000 }, { "type": "card_transaction", "txn_id": "txn_01HZY", "amount_cents": 206043 } ], "completed_at": "2026-05-19T10:14:22Z"}Reconcile your books from the lines array — each line points back to the original transaction or top-up that contributed.
3. Listening for completion
The reliable way to know a settlement landed:
// In your webhook handlerif (event.type === "settlement.completed") { const settlement = event.data.settlement; await db.settlements.upsert(settlement); await ledger.recordUSDCInflow({ amount: settlement.usdc_amount, txHash: settlement.on_chain.tx_hash, settlementId: settlement.id, });}We also fire settlement.failed if the on-ramp leg fails (rare; usually a Bridge-side compliance hold). The settlement enters manual_review; our treasury ops team contacts you within one business day.
4. Paying out from USDC
To convert USDC back to fiat (off-ramp), create a payout:
const payout = await qp.payouts.create( { amount_cents: 1000000, // $10,000 destination: { bank_account_id: "ba_01HZX" }, speed: "next_business_day", }, { idempotencyKey: crypto.randomUUID() },);Off-ramps settle T+1 to U.S. bank accounts and T+2 internationally. payout.completed fires when the wire lands.
5. On-chain payouts
To pay another Aptos address directly (e.g., paying a vendor in USDC), use an on-chain payout:
await qp.payouts.create({ amount_usdc: "1500.00", destination: { aptos_address: "0xbeef..." },});This is screened against sanctions and the Travel Rule before broadcast. Counterparties on the OFAC SDN list or other restricted lists are blocked at the application layer.
Treasury reporting
Daily reconciliation reports land in the dashboard and via email at the address on your treasury config. The API exposes the same data:
const report = await qp.treasury.reports.retrieve({ date: "2026-05-18" });The report covers opening balance, settlements in, payouts out, fees, and closing balance — denominated in both USD and USDC.
What to read next
- Webhooks → Event catalog — every settlement and payout event.
- Compliance — the regulatory framing for the USDC leg.