@faremeter/payment-solana/flex/facilitator and @faremeter/flex-solana/facilitator. For the protocol-level model, see Flex Concepts.
Two layers of API
| Layer | Package | Use it for |
|---|---|---|
| Plug-in | @faremeter/payment-solana/flex/facilitator | A drop-in FacilitatorHandler that integrates with Faremeter middleware. |
| Building blocks | @faremeter/flex-solana/facilitator | Hold manager, escrow accounting, split merging — for custom integrations. |
The plug-in: createFacilitatorHandler
FlexFacilitator is a FacilitatorHandler (so it slots into Faremeter’s facilitator service) plus three extras:
flush()— drain settled in-memory holds to chain immediately.getHoldManager()— inspect the in-memory hold state (debugging, metrics).stop()— cancel the background flush interval.
flushIntervalMs), so most operators never need to call flush() themselves.
Verify and settle
The handler implements the standard Faremeterverify / settle lifecycle:
-
verify— decodes the client’sFlexPaymentPayload, checks the Ed25519 signature, fetches escrow + session-key state, runstryHoldon the in-memory hold manager, and returns success if the reservation took. The hold initially reserves the fullmaxAmount;settlereduces it later. Plan escrow capacity against the ceiling, not the expected actual cost. -
settle— the middleware reports the actual amount consumed. The handler updates the hold’ssettleAmount(must be<=the previously heldmaxAmount), marks itsettled, and the next flush pushes it on-chain. The handler returns the x402 settle response immediately; on-chain confirmation is asynchronous. -
flush(background) — collects allsettledholds, buildssubmit_authorizationinstructions in batches, signs them with the facilitator key, and tracks confirmation. Once submitted, holds becomesubmitted. After the refund window closes, the handler buildsfinalizeinstructions to release funds.
PERMANENT_SUBMIT_ERRORS (expired authorizations, invalid signatures, expiry-too-far, etc.) are not retried — the hold is dropped and an error is logged. Transient errors retry up to maxSubmitRetries times with submitRetryDelayMs between attempts.
Middleware integration: createUptoHandler
For variable-amount endpoints (the canonical Flex use case), @faremeter/payment-solana/flex/hono exposes createUptoHandler. It takes an authorize callback that decides the maximum amount for a given request, then a handle callback that does the work and reports the actual amount via a settle function.
Building blocks: hold manager
UsecreateHoldManager directly if you’re building outside the Faremeter middleware abstraction.
| State | Meaning |
|---|---|
held | Reserved in memory; merchant work has not yet completed. |
settled | Actual amount known; ready to be flushed on-chain. |
submitting | A submit_authorization transaction is in flight. |
submitted | Pending settlement exists on-chain; waiting for refund window to close. |
finalizing | A finalize transaction is in flight to release funds to recipients. |
MAX_PENDING_SETTLEMENTS = 16.
Building blocks: accounting
fetchEscrowAccounting is the snapshot you take from chain to feed the hold manager:
snapshotMaxAgeMs, default 10 seconds) to avoid hammering RPC.
Building blocks: split merging
When the merchant runs the same recipient through multiple split entries (for example, a base fee + a referral kick-back going to the same operator),mergeSplits collapses duplicates:
FLEX_ERROR__DUPLICATE_SPLIT_RECIPIENT).
Operational considerations
- Activity tracking.
last_activity_slotis only updated bysubmit_authorizationandrefund(both require facilitator signatures).finalizeis permissionless — even cranking it forever doesn’t keep the deadman timer alive. Make sure your facilitator submits or refunds at least once perdeadman_timeout_slots, even on quiet escrows. - Refund-window hygiene. Honor refund requests from middleware (failed deliveries, disputes) by issuing
refundinstructions during the window. Once the window closes,finalizeis the only remaining lever. - Pending-count headroom. With the cap at 16, a busy escrow saturates fast. Submit and finalize aggressively so middleware verify calls don’t get rejected for capacity.
- Session-key grace period. The facilitator should surface a documented submission SLA so clients can pick a
revocation_grace_period_slotsthat’s at least 2x the SLA. The default minimum the plug-in enforces is150slots (~1 minute).
Further reading
- Concepts — the protocol-level model.
- Program Reference — on-chain instructions, accounts, and constraints.
- API Reference — the full
@faremeter/flex-solanasurface. - Facilitators — how facilitators fit into Faremeter overall.