> ## Documentation Index
> Fetch the complete documentation index at: https://glide-9da73dea.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# @glideco/x402-facilitator

> x402 facilitator protocol shapes and a composable screening pipeline. Pure functions; settlement IO is injected by apps/web.

x402 facilitator protocol layer with Chainalysis-backed compliance screening.
x402 facilitators verify off-chain payment payloads and settle them on-chain.
The pipeline composes address screening, MCC screening and idempotent
settlement. Screening coverage depends on the configured provider and its
contract; the protocol package does not itself provide a regulated service.

This package is the protocol shape and orchestration layer: `VerifyRequest`,
`VerifyResponse`, `SettleRequest`, `SettleResponse`, and the compliance-pipeline
composer. Actual on-chain RPC calls, Chainalysis API invocations, and audit-event
writes live in `apps/web`. The HTTP endpoints are mounted from
`app/api/x402/facilitator/{verify,settle}/route.ts`.

**F1 IRON RULE:** The facilitator's `SettleResponse.txHash` is the facilitator's
claim, not verified fact. Operators MUST independently RPC-verify the on-chain
transaction before persisting it to any audit row. This package surfaces the
facilitator's response verbatim and leaves the verification step to the consumer.
The reference implementation is the `serverFetchChainTx` dependency in the MCP
`x402.pay` tool.

## Install

```bash theme={null}
npm install @glideco/x402-facilitator
```

[npmjs.com/package/@glideco/x402-facilitator](https://www.npmjs.com/package/@glideco/x402-facilitator)

## Two-phase protocol

x402 uses a verify-then-settle protocol:

1. **`/verify`** — facilitator validates the off-chain EIP-712 payment payload and
   runs the compliance pipeline. Returns `{isValid, invalidReason}` without
   touching chain state.
2. **`/settle`** — facilitator broadcasts the on-chain transaction after a
   TOCTOU re-verify pass. Returns `{success, txHash, network}`.

The `handleVerify` and `handleSettle` orchestrators implement this contract.
Settlement uses a store-before-broadcast pattern: a pending sentinel is written
before invoking broadcast so a process kill mid-broadcast does not re-broadcast
on replay.

## API surface

| Export | Description |
| - | - |
| `handleVerify(rawRequest, deps)` | Parse + validate payload, run compliance pipeline, return `VerifyResponse`. |
| `handleSettle(rawRequest, deps)` | Re-verify (TOCTOU defense), store sentinel, broadcast, store terminal state. |
| `runCompliancePipeline(args, screener)` | Compose sanctions + MCC + cap screening. Short-circuits on first block. |
| `deriveIdempotencyCacheKey(args)` | Content-bound cache key: `${idempotencyKey}:${sha256(payTo\|network\|payload)}`. |
| `FACILITATOR_MAX_BODY_BYTES` | 4 MB — request size limit to bound CPU + memory. |
| `X402_FACILITATOR_VERSION` | `'2.0'` — version echoed in `X-X402-Version` response header. |

## Wiring the /verify route

```ts theme={null}
// apps/web/src/app/api/x402/facilitator/verify/route.ts
import {
  handleVerify,
  FACILITATOR_MAX_BODY_BYTES,
  X402_VERSION_HEADER,
  X402_FACILITATOR_VERSION,
} from '@glideco/x402-facilitator';
import { chainalysisScreener } from '@/server/lib/screeners';

export async function POST(req: Request) {
  if (Number(req.headers.get('content-length') ?? 0) > FACILITATOR_MAX_BODY_BYTES) {
    return new Response(null, { status: 413 });
  }
  const body = await req.json();
  const result = await handleVerify(body, {
    async decodePayload({ payload, network }) {
      // Validate EIP-712 signature, check expiry + replay
      return eip712Decoder.decode(payload, network);
    },
    screener: chainalysisScreener,
  });

  return Response.json(result, {
    headers: { [X402_VERSION_HEADER]: X402_FACILITATOR_VERSION },
  });
}
```

## Compliance pipeline

The pipeline is composable — each screener returns `'allow' | 'block' | 'review'`.
The first non-allow result short-circuits; `'review'` is treated as block (conservative
posture).

```ts theme={null}
import { runCompliancePipeline, type ComplianceScreener } from '@glideco/x402-facilitator';

const screener: ComplianceScreener = {
  async screenSanctions({ payerAddress, payeeAddress, network, asset, amount }) {
    const verdict = await chainalysis.screenAddress(payerAddress);
    return {
      verdict: verdict.risk === 'high' ? 'block' : 'allow',
      reason: verdict.reason ?? 'ok',
      provider: 'chainalysis',
      screeningId: verdict.screeningId,
    };
  },
  async screenMcc({ mcc, payeeAddress }) {
    return mccEngine.check({ mcc, payeeAddress });
  },
};

const result = await runCompliancePipeline({
  payerAddress: '0xPayer…',
  payeeAddress: '0xMerchant…',
  network: 'base',
  asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  amount: '1000000',
}, screener);

if (result.verdict !== 'allow') {
  console.log('Blocked by:', result.blockingResult);
}
```

## Idempotency defense

The cache key is content-bound to defend against cross-tenant cache poisoning.
An attacker who guesses a victim's idempotency key also needs to match the
exact `(payTo, network, paymentPayload)` triple:

```ts theme={null}
import { deriveIdempotencyCacheKey } from '@glideco/x402-facilitator';

const cacheKey = deriveIdempotencyCacheKey({
  idempotencyKey: request.idempotencyKey,
  payTo: request.paymentRequirements.payTo,
  network: request.paymentRequirements.network,
  paymentPayload: request.paymentPayload,
});
// → 'user-supplied-key:a3f8b2c1…' (SHA-256 prefix of content triple)
```

## Verify response invalidReason vocabulary

| Reason | Cause |
| - | - |
| `insufficient_funds` | Payload amount exceeds on-chain balance. |
| `invalid_signature` | EIP-712 signature verification failed. |
| `expired` | Payment payload past `validBefore`. |
| `replayed` | Nonce already consumed. |
| `sanctions_block` | Payer or payee matched an OFAC / sanctions entry. |
| `mcc_blocked` | Merchant category code on the deny list. |
| `amount_exceeds_policy_cap` | Amount exceeds the policy-engine cap for this agent. |
| `velocity_exceeded` | Per-period transaction velocity cap hit. |

## Reading list

* [Money-safety contracts](/oss/concepts/money-safety-contracts) — the
  F-rules, including F1 (server-side RPC verify) that governs `txHash` handling.
* [`@repo/connectors-coinbase-x402`](/oss/packages/connectors-coinbase-x402) (workspace-internal — wraps `@glideco/x402-facilitator` with Coinbase CDP integration) —
  Coinbase CDP integration that wraps this facilitator for receiver-side flows.
* [Source on GitHub](https://github.com/darshanbathija/axtior-neobank/tree/main/packages/x402-facilitator)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.