> ## Documentation Index
> Fetch the complete documentation index at: https://docs.faremeter.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Flex Concepts

> Escrow accounts, session keys, splits, holds, settlement, refund windows, and deadman switch.

This page explains the protocol-level building blocks of the Flex scheme. Implementation details for the Solana program live in the [Program Reference](/flex/program-reference).

## Participants

| Role            | Responsibility                                                                             |
| --------------- | ------------------------------------------------------------------------------------------ |
| **Client**      | Funds the escrow, signs payment authorizations off-chain with a session key.               |
| **Middleware**  | Generates payment requirements, gates the resource, and negotiates a hold with the client. |
| **Facilitator** | Validates authorizations, runs settlement policy, and submits authorizations on-chain.     |

The middleware and facilitator can be the same service or separate services that communicate via API. Faremeter middleware delegates verify/settle to a facilitator over HTTP.

## Escrow accounts

An escrow is a prepaid balance held by the on-chain program on behalf of a single client and a single facilitator. It can hold multiple token mints. Each escrow is parameterized by:

* `refund_timeout_slots` -- how long a pending settlement waits before finalizing. Bounded between \~150 slots (\~1 minute) and \~1,296,000 slots (\~6 days).
* `deadman_timeout_slots` -- how long the facilitator can be inactive before the client can unilaterally close. Bounded between \~1,000 slots (\~6.7 minutes) and \~2,592,000 slots (\~12 days). Must be at least `2 * refund_timeout_slots`.
* `max_session_keys` -- caps the number of registered session keys. `0` means unlimited.

A client creates a separate escrow per facilitator they work with. The PDA also includes a numeric `index`, so a single client may hold multiple escrows with the same facilitator.

Once created, the escrow contract requires **dual authorization** for any transfer out: the client's session-key signature on a payment authorization, plus an on-chain transaction signature from the registered facilitator. Neither party can move funds unilaterally.

## Session keys

Session keys are Ed25519 keypairs that the client registers on-chain to sign payment authorizations off-chain. They exist so that:

* The client never needs to sign with the escrow account's private key on every request.
* Smart wallets, multisigs, and custodial wallets work natively. None of them can sign arbitrary off-chain messages, but they can sign the on-chain transaction that registers a session key.
* Keys can be revoked unilaterally by the client. A configurable grace period (`revocation_grace_period_slots`) lets the facilitator settle in-flight authorizations after revocation but before the key becomes fully invalid.

Session keys carry no spending limits of their own. Limits are expressed per-authorization. If you need to bound exposure, fund a smaller escrow or use a key with a short `expires_at_slot`.

## Payment authorizations

A payment authorization is a client-signed message that authorizes a single payment from the escrow. The signed fields are:

| Field             | Description                                                                        |
| ----------------- | ---------------------------------------------------------------------------------- |
| `programId`       | The Flex program ID (binds the signature to a specific deployment).                |
| `escrow`          | Escrow PDA the payment is drawn from.                                              |
| `mint`            | SPL token mint to settle in.                                                       |
| `maxAmount`       | Ceiling the facilitator may settle up to. The actual `settle_amount` can be lower. |
| `authorizationId` | Random `u64` identifier; provides on-chain replay protection via PDA seeds.        |
| `expiresAtSlot`   | Slot after which the authorization may not be submitted.                           |
| `splits`          | Recipient list with basis-point allocations summing to 10,000.                     |

The facilitator can only submit what the client signed. They cannot raise the amount, change the mint, or alter the split distribution.

### Splits

Splits encode multi-recipient settlement directly into the signed authorization. Each entry is `(recipient_token_account, bps)` and the entries must sum to exactly `10000` (100%). A single-recipient payment is a one-entry split with `10000` bps.

Splits enable platform fees, referral commissions, royalties, and facilitator fees in a single atomic settlement. The on-chain program distributes funds proportionally at finalize time. The current Solana program supports up to **5** splits per authorization.

## Holds

When a request arrives, the middleware and facilitator coordinate a hold before any work is done:

1. **Hold request.** The middleware tells the client the maximum amount the operation may consume.
2. **Client authorization.** The client signs an authorization for `maxAmount` (which may be larger than the requested amount, leaving headroom for variable cost).
3. **Hold validation.** The middleware forwards the signed authorization to the facilitator. The facilitator validates the signature, confirms sufficient escrow capacity, and reserves it in memory.
4. **Service delivery.** With the hold reserved, the middleware performs the work.
5. **Settlement.** The middleware reports the actual amount consumed. The facilitator converts the in-memory hold to an on-chain pending settlement at the actual amount used.

Holds are tracked off-chain by the facilitator in memory. They keep the in-flight commitments visible without burning a transaction per request. When the facilitator decides to submit an authorization on-chain, it picks the actual amount used (which must be `<= maxAmount`) and turns the hold into a pending settlement.

## Pending settlements and the refund window

A `submit_authorization` instruction creates a `PendingSettlement` PDA with:

* `amount` -- the actual amount being settled (the hold's `settleAmount`, not the ceiling).
* `original_amount` and `max_amount` -- preserved for audit.
* `submitted_at_slot` and `expires_at_slot`.

The pending settlement can be modified or finalized as follows:

* **Refund window.** Until `submitted_at_slot + refund_timeout_slots` elapses, the facilitator may call `refund` to reduce or cancel the amount. This is how the system handles failed deliveries or disputes the facilitator agrees with.
* **Finalize.** After the refund window closes, anyone can call `finalize` to distribute funds per the signed splits and close the pending settlement PDA. The rent for the PDA is returned to the facilitator.
* **Void on deadman.** If the deadman switch fires, all pending settlements are voided and the funds remain in the escrow.

The refund window is enforced on-chain, not by facilitator policy. The merchant is guaranteed to be paid after it closes (assuming sufficient escrow balance), and the client is guaranteed recourse during it.

The on-chain program caps the number of concurrent pending settlements per escrow at `MAX_PENDING_SETTLEMENTS = 16`. Facilitators must finalize older settlements before submitting new ones once the cap is reached.

## Deadman switch

If the facilitator becomes unresponsive -- no `submit_authorization`, no `refund` -- the client can recover funds without facilitator cooperation once `last_activity_slot + deadman_timeout_slots` has elapsed.

The recovery is a three-step sequence:

1. **`void_pending`** for each open pending settlement. Either the owner or the facilitator can call this once the deadman timer has expired (or once a pending settlement has been sitting past `submitted_at_slot + refund_timeout_slots + deadman_timeout_slots`). Funds reserved behind the pending PDA return to the vault.
2. **`revoke_session_key` + `close_session_key`** for each registered session key. `emergency_close` requires `session_key_count == 0`.
3. **`emergency_close`** -- owner-only. Drains all vault token accounts to owner-controlled destinations and closes the escrow PDA.

`last_activity_slot` is only updated by instructions that require the facilitator's signature (`submit_authorization`, `refund`). Permissionless instructions like `finalize` and `deposit` do not reset the timer. This prevents a malicious facilitator from holding funds hostage by cranking finalizations while ignoring new business.

The deadman switch guarantees that funds are never permanently locked, regardless of facilitator behavior. Choose a `deadman_timeout_slots` that balances client patience against the facilitator's legitimate downtime tolerance.

## Replay protection and expiry

Each authorization carries a unique `authorization_id`. The pending-settlement PDA seeds include this ID, so a duplicate `submit_authorization` fails at account initialization. `expires_at_slot` provides a second layer: an authorization that the facilitator delays past its expiry can no longer be submitted.

The on-chain program also bounds how far in the future an expiry may be: at submission time, `expires_at_slot` must be `<= current_slot + escrow.refund_timeout_slots`. This caps a stale authorization's settlement window to the same horizon as the refund window.

## Security model at a glance

| Compromised parties       | Severity | What attacker can do                                                        |
| ------------------------- | -------- | --------------------------------------------------------------------------- |
| Middleware alone          | None     | Cannot sign; can only forward authorizations the client signed.             |
| Session key alone         | Low      | Can sign authorizations, but cannot submit them without facilitator co-op.  |
| Session key + facilitator | Critical | Can drain up to signed `maxAmount` per authorization via fraudulent splits. |

Recommended mitigations: confirm split recipients before signing, use short-lived session keys, fund escrows based on expected usage, and monitor on-chain pending settlements. See the security note in the [Program Reference](/flex/program-reference#security).

## Further reading

* [Quickstart](/flex/quickstart) -- end-to-end client flow with `@faremeter/flex-solana`.
* [Facilitator](/flex/facilitator) -- operator-side hold management and settlement.
* [Program Reference](/flex/program-reference) -- on-chain instructions, account layouts, and constants.
* [Payment Schemes](/concepts/payment-schemes) -- where Flex sits among Faremeter's other schemes.
