# Agent flow — check before signing

The point of a preflight is that it happens **before** the irreversible step. For an
XRPL agent, the irreversible step is signing. Everything below is the contract we
actually run in production; the field names come from a mainnet canary, not from a
specification draft.

```
  agent decides to pay
          │
          ▼
  ┌───────────────────────┐
  │ 1. POST the intent    │   no X-PAYMENT header yet
  │    to the preflight   │
  └───────────┬───────────┘
              ▼
          HTTP 402  ──►  accepts[0]: payTo, amount, network, extra.invoiceId, extra.sourceTag
              │
              ▼
  ┌───────────────────────┐
  │ 2. pay 1000 drops     │   a separate, tiny XRPL payment — the fee for the check
  │    sign it yourself   │   your key never leaves your side
  └───────────┬───────────┘
              ▼
  ┌───────────────────────┐
  │ 3. repeat the POST    │   X-PAYMENT: base64(canonical PaymentPayload)
  │    with the proof     │
  └───────────┬───────────┘
              ▼
          HTTP 200  ──►  decision: ALLOW | REVIEW | BLOCK   + receipt + PAYMENT-RESPONSE header
              │
      ┌───────┴────────┐
      │                │
   ALLOW            not ALLOW
      │                │
      ▼                ▼
  sign the         do NOT sign.
  real payment     escalate to a human,
                   keep the receipt as the reason
```

## The rule that makes this worth doing

**Only `decision == "ALLOW"` may lead to a signature.** Treat everything else —
`REVIEW`, `BLOCK`, a transport error, a timeout, a malformed body, a missing
`decision` field — as *do not sign*. A preflight that fails open is not a preflight.

## Two things that are easy to get wrong

**The fee payment is not the payment under review.** Step 2 pays 1000 drops
(0.001 XRP) to us so the check runs. The payment your agent actually intends to make
is described in the request body and is *never* executed by us. We evaluate it; you
sign it — or don't.

**`SourceTag` in the challenge is the facilitator's, not yours.** `extra.sourceTag`
in the 402 belongs to the fee payment. The `source_tag` inside your intent body is
your own value, and it is echoed back in `evaluated_terms` untouched.

## Binding the fee payment to the invoice

From the 402 challenge you get `extra.invoiceId` (32 hex chars). The XRPL payment
must bind to it in both places:

- `InvoiceID` = `sha256(invoiceId_utf8).hex().upper()` — 64 hex chars
- `Memos[0].Memo.MemoData` = `hex(utf8(invoiceId)).upper()`

Give the transaction a deadline that is shorter than the invoice's:
`LastLedgerSequence = latest_validated_ledger + ceil(maxTimeoutSeconds / 5) + 2`.

The `X-PAYMENT` header is
`base64(json.dumps(payload, sort_keys=True, separators=(",",":")))` over:

```json
{
  "x402Version": 2,
  "accepted": { "scheme": "...", "network": "...", "amount": "...", "asset": "...",
                "payTo": "...", "maxTimeoutSeconds": 600, "extra": { } },
  "payload":  { "invoiceId": "...", "signedTxBlob": "..." }
}
```

`accepted` is copied from the 402 you received — those seven keys, unchanged. Sending
back a challenge you did not receive will not settle.

## What you keep afterwards

The 200 response carries a `receipt` and a `PAYMENT-RESPONSE` header. The receipt is
the artefact worth storing: it carries `request_digest`, the decision, the policy and
authority that produced it, and `fee_settlement.transaction` — the on-ledger hash of
the fee you just paid. That last field is what makes the record checkable by someone
who does not trust us: they can look the transaction up themselves.

A synthetic example of the shape — placeholders only, no real call and no on-ledger
execution — is at [`receipt.example.json`](/xrpl/receipt.example.json). Its
`receipt_hash` is generated from exactly that file with the production formula, and the
file carries the command to recompute it.

## Idempotency

Replaying the same `X-PAYMENT` header returns the same delivered result rather than
charging again. One paid invoice, one delivery.

---

Endpoints, worked examples in three languages and the mainnet proofs:
<https://agentnomos.com/xrpl>

Preflight classification only. Not legal advice.
