Skip to main content

Settlement

Settlement is the process of transferring funds from the escrow to the receiver. The facilitator handles this automatically.
The escrow settlement is powered by Base’s Commerce Payments Protocol, implementing the authorize-capture pattern used by traditional payment processors like Stripe and Adyen.

Capture Strategy

The facilitator uses a batched capture strategy to minimize gas costs:
TriggerAction
Pending > $1Batch capture (cron job)
Expiry < 2hBatch capture (cron job)
Expiry < 30minSync capture (per request)
Captures are batched to reduce gas costs. Multiple pending amounts from different sessions are captured in a single transaction when possible.

Settlement Flow

Exact vs Escrow Settlement

Exact Scheme

1 transaction per request
  • ERC-3009 transferWithAuthorization
  • Immediate on-chain transfer
  • Higher gas cost per call
  • Best for infrequent, high-value calls

Escrow Scheme

1 transaction to create session
  • Session creation: 1 tx
  • Session usage: 0 tx (off-chain)
  • Batch capture: amortized gas
  • Best for frequent, low-value calls

Session Timeline

Each session has two critical timestamps:
TimestampDefaultMeaning
authorizationExpiry+1 hourDeadline for facilitator to capture
refundExpiry+25 hoursOnly affects refund() function (for captured amounts)
refundExpiry does NOT affect reclaim. The payer can call reclaim() on the contract anytime after authorizationExpiry - there is no upper time limit.

Who Can Do What, When

Critical: If the facilitator doesn’t capture pending amounts before authorizationExpiry, those funds are forfeited - the receiver loses them and the user can reclaim the full remaining balance.

Before authorizationExpiry

ActorCan DoHow
FacilitatorCapture pending amountsAutomatic (cron job)
UserReclaim unused fundsAPI: POST /api/payer/sessions/{id}/reclaim
When user reclaims via API:
  1. Facilitator captures any pending amount first → receiver gets paid
  2. Facilitator voids remaining → user gets refund

After authorizationExpiry

ActorCan DoHow
Facilitator❌ Cannot captureAuthorization expired
UserReclaim ALL remainingAPI or direct contract call
When user reclaims after auth expiry:
  1. Pending amounts are forfeited (receiver loses them)
  2. User gets back: authorized - captured (everything not yet captured)
The reclaim API works both before and after authorizationExpiry. The difference is that after expiry, the facilitator cannot capture pending amounts first - they are forfeited.

Reclaim API

POST /api/payer/sessions/{id}/reclaim
Authorization: Bearer <JWT>
Response (before auth expiry):
{
  "success": true,
  "reclaimedAmount": "8000000",  // $8 returned to user
  "capturedAmount": "2000000",   // $2 captured for receiver
  "voidTxHash": "0x...",
  "captureTxHash": "0x..."
}
Response (after auth expiry):
{
  "success": true,
  "reclaimedAmount": "10000000", // Full $10 returned (pending forfeited)
  "capturedAmount": "0",
  "voidTxHash": "0x..."
}
The reclaim API works both before and after authorizationExpiry. Before expiry, it captures pending amounts first (receiver gets paid). After expiry, pending amounts are forfeited and you get back everything not yet captured.

Balance Visualization

Understanding how a session balance changes over time ($10 deposit example):
1

Initial - After session creation

Full deposit is available for API calls.
2

After API calls - Spent $2.50

Pending = owed to receiver, not yet on-chain.
3

After batch capture

Facilitator captured pending → transferred on-chain to receiver.
4

After reclaim - Session closed

User gets unused funds back. Session closed.
Available = can be spent on API calls. Pending = owed to receiver, not yet on-chain. Captured = transferred on-chain to receiver.

Gas Costs

OperationGas (approx)Who Pays
Session creation~150kFacilitator
Batch capture~80k per sessionFacilitator
Reclaim (via API)~100kFacilitator
Reclaim (direct)~80kUser
Gas costs are covered by the facilitator and factored into the service fee.

Refund vs Reclaim

These are two different contract functions - don’t confuse them:
FunctionPurposeWho CallsWhen
reclaim()Get back uncaptured fundsPayerAfter authorizationExpiry
refund()Get back already-captured fundsOperator (facilitator)Before refundExpiry

Reclaim (Implemented ✅)

For unused session balance that was never captured:
User deposits $10 → Uses $3 → Facilitator captures $3 → User reclaims $7
The payer calls reclaim() directly on the contract after authorizationExpiry to get back any amount that wasn’t captured.

Refund (Not Yet Implemented 🔜)

What is a refund? When an API provider (receiver) voluntarily returns money they already received back to the user. When would you need this?
ScenarioExample
Service failureYour API returned an error but the user was still charged
Goodwill gestureUser complains, you decide to refund as good customer service
Accidental overchargeYou charged 5butmeanttocharge5 but meant to charge 0.50
Partial refundUser paid for 10 API calls, only 7 worked
Receiver-initiated only. Only the API provider (receiver) can trigger refunds. The facilitator executes the request - it does not arbitrate disputes.If you’re a payer with a complaint, contact the API provider directly.
How is this different from reclaim?
RECLAIM: User deposited $10, used $3, wants the unused $7 back
         → User gets back money that was NEVER captured

REFUND:  User deposited $10, used $10, API failed on a $2 call
         → Receiver gives back $2 that WAS captured (receiver already has it)
Not yet available via API. The refund() function exists in the smart contract but the facilitator doesn’t expose it yet. Coming soon.

How Refund Will Work (When Implemented)

ConstraintValue
Who can requestReceiver (API provider) only
Facilitator roleExecutes only (no arbitration)
Max refund amountTotal captured for that session
Time limitBefore refundExpiry (default: +25 hours from session creation)
After refundExpiry, the contract’s refund() function is locked and refunds are no longer possible through the escrow system.