XRPL Exact Scheme
Detailed specification for the XRPL presigned payment scheme used by x402.
Overview
The XRPL Exact scheme uses presigned Payment transactions to enable trustless, atomic payments between clients and resource servers.
Network Identifiers (CAIP-2)
x402 uses CAIP-2 network identifiers. For XRPL, the format is xrpl:{network_id}
Mainnet
xrpl:0Testnet
xrpl:1Devnet
xrpl:2x402 v2 HTTP Headers
| Direction | Header | Description |
|---|---|---|
| Server → Client | PAYMENT-REQUIRED | Payment challenge (base64 JSON) |
| Client → Server | PAYMENT-SIGNATURE | Signed payment payload (base64 JSON) |
| Server → Client | PAYMENT-RESPONSE | Settlement result (base64 JSON) |
Payment Payload Format
The PAYMENT-SIGNATURE header contains a base64-encoded JSON payload.
Example: XRP Payment
{
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "xrpl:1",
"asset": "XRP",
"payTo": "rDestinationAddress...",
"amount": "1000000",
"maxTimeoutSeconds": 600,
"extra": {
"sourceTag": 804681468,
"invoiceId": "INV-abc123"
}
},
"payload": {
"signedTxBlob": "1200002280000000..."
}
}Example: IOU Payment (e.g., RLUSD)
{
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "xrpl:1",
"asset": "524C555344000000000000000000000000000000",
"payTo": "rDestinationAddress...",
"amount": "0.01",
"maxTimeoutSeconds": 600,
"extra": {
"sourceTag": 804681468,
"issuer": "rIssuerAddress...",
"invoiceId": "INV-abc123"
}
},
"payload": {
"signedTxBlob": "1200002280000000..."
}
}For IOUs, the asset must be a 3-character code (e.g., "USD") or a 160-bit hex currency code. The issuer is required in extra.
Asset Types
| Asset | Amount Format | Example | Extra Fields |
|---|---|---|---|
"XRP" | Drops (string integer) | "1000000" = 1 XRP | None |
"USD" or hex | Decimal string | "0.01" | issuer (required) |
Note: 1 XRP = 1,000,000 drops. When pricing in XRP, always specify the amount in drops as a string.
Payment Requirements Fields
The PAYMENT-REQUIRED header advertises these fields in the accepts array:
| Field | Required | Description |
|---|---|---|
scheme | Yes | Always "exact" |
network | Yes | CAIP-2 identifier (e.g., "xrpl:1") |
asset | Yes | "XRP" or currency code |
payTo | Yes | XRPL classic address to receive payment |
amount | Yes | Amount (drops for XRP, decimal for IOU) |
maxTimeoutSeconds | Yes | Max validity window for payment |
extra.invoiceId | Yes | Unique invoice identifier |
extra.sourceTag | Yes | XRPL SourceTag (default 804681468) |
extra.issuer | IOU only | Issuer address for IOUs |
extra.destinationTag | Optional | Destination tag if required |
Invoice Binding (Security)
To prevent replay attacks, the signed transaction MUST commit to the invoice. The facilitator accepts two binding methods:
Method A: Memos
Include a memo where MemoData equals the invoice ID (hex-encoded UTF-8).
MemoData = HEX(UTF-8(invoiceId))Method B: InvoiceID
Set the transaction's InvoiceID field to SHA-256 of the invoice ID.
InvoiceID = SHA256(invoiceId)Important: Without invoice binding, a single valid payment could be replayed against multiple invoices. The facilitator rejects transactions missing valid binding.
Verification Process
The facilitator performs these checks before accepting a payment:
Envelope checks
x402Version = 2, scheme = "exact", network supported
Decode transaction
Decode signedTxBlob from hex, parse XRPL binary format
Transaction type
Must be a Payment transaction
Destination
tx.Destination must match payTo address
Network binding
NetworkID field must match CAIP-2 network rules
Amount matching
DeliverMax/Amount must match required amount
Expiry check
LastLedgerSequence must be present and within limits
Invoice binding
Memos or InvoiceID must bind to invoiceId
Policy checks
Fee limits, no partial payments, no cross-currency
Settlement Response
On successful settlement, the PAYMENT-RESPONSE header contains:
{
"success": true,
"transaction": "ABC123...txhash",
"network": "xrpl:1",
"payer": "rPayerAddress..."
}Common Error Codes
| Code | Note |
|---|---|
invalid_network | The network is mismatched, unsupported, or not a valid xrpl:<network_id> value. |
payment_requirements_mismatch | The accepted payment terms do not exactly match the server's required terms. |
invalid_tx_blob | The signedTxBlob cannot be decoded as a valid XRPL transaction. |
not_payment_tx | The decoded transaction is not a Payment transaction. |
destination_mismatch | The transaction destination does not match the required payTo address. |
source_tag_mismatch | SourceTag is missing, invalid, or different from the required SourceTag. |
amount_mismatch | The transaction amount field/value is missing or does not match the required amount. |
invoice_binding_missing | No invoice binding is present in MemoData or InvoiceID. |
invoice_binding_mismatch | The invoice binding exists, but it points to a different invoice. |
missing_last_ledger_sequence | LastLedgerSequence is missing, so the payment has no bounded expiry. |
Security Considerations
- • Invoice replay: Always enforce invoice binding to prevent cross-resource reuse
- • Network replay: Bind to intended network via CAIP-2 and NetworkID rules
- • Expiry: Require LastLedgerSequence and cap maximum horizon
- • Idempotency: Consume invoices once settlement succeeds