Specification
Wire format
The exact HTTP shape of a paid action — request, 402 challenge, payment, retry, and 200 with receipt.
402 challenge
The first request to an action endpoint MUST omit the Authorization header.
request 1
http
POST /api/actions/extract.structured HTTP/1.1
Host: example.com
Content-Type: application/json
{ "doc_id": "doc.foo" }The publisher responds with HTTP 402 and the L402 challenge:
response 1
http
HTTP/1.1 402 Payment Required
Content-Type: application/json
WWW-Authenticate: L402 macaroon="<base64>", invoice="lnbc…"
{
"error": "payment_required",
"action_id": "extract.structured",
"amount_msats": 1000,
"invoice": "lnbc10n1p…",
"payment_hash": "9bb6…",
"token": "<base64>",
"expires_at": 1777160234
}L402 token
The token is opaque to the agent. It is structured for stateless verification on the publisher side; the recommended encoding is:
text
base64url(JSON_BODY) "." base64url(HMAC_SHA256(secret, base64url(JSON_BODY)))
JSON_BODY = {
"ph": payment_hash,
"sc": action_id ":" sha256(canonical_input),
"exp": unix_seconds,
"n": random_nonce
}Equivalent macaroon-formatted tokens are accepted. The wire format only cares that the token is opaque, parseable in a known format, and that the publisher can verify it.
Retry with proof
request 2
http
POST /api/actions/extract.structured HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: L402 <token>:<preimage>
{ "doc_id": "doc.foo" }The agent supplies the token returned in the 402, plus the Lightning preimage from its wallet. The publisher verifies:
- ·Token signature (HMAC valid).
- ·Token scope matches
action_id+ canonical input hash. - ·Token
expin the future. - ·Either:
sha256(preimage) == payment_hash(cryptographic), OR the publisher's wallet reports the invoice as settled (operational fallback). - ·Token has not been previously consumed.
On success the publisher returns:
response 2
http
HTTP/1.1 200 OK
Content-Type: application/json
{
"output": { … },
"receipt": { …signed receipt… }
}Error responses
| Status | Code | When |
|---|---|---|
| 400 | invalid_input | Input fails the action's input_schema. |
| 401 | invalid_or_expired_token | Token signature invalid or expired. |
| 401 | preimage_mismatch | sha256(preimage) ≠ payment_hash. |
| 401 | token_already_consumed | Token was previously redeemed. |
| 402 | payment_required | Initial 402 (challenge issuance). |
| 425 | payment_not_confirmed | Settle status not yet visible at publisher's wallet. |
| 503 | invoice_creation_failed | Publisher's wallet temporarily unable to issue invoices. |
ⓘ425 vs 402
425 (Too Early) signals “your payment is in flight, retry the same request shortly.” The agent does NOT need to pay again; it just retries with the same Authorization header.
Timing & retries
- ·Agents SHOULD wait at least 1 s between 425 retries; back off to 5 s by attempt 3.
- ·Agents SHOULD give up after 30 s of 425 responses and surface the failure.
- ·Publishers SHOULD set a token
expof 5–15 minutes after issuance. - ·Publishers SHOULD NOT consume a token until they have actually issued the receipt.
Next
Receipt format
Exact JSON shape, canonicalization rules, and signature verification.
agents402.org / 2026
Open protocol · v0.1