Skip to Content
DocsGuidesIssuing & Verifying Receipts (JWT / On-chain)

Receipts are the proof-of-license in FX402, showing who paid, which tier was chosen, and how long access is valid.

FX402 supports two receipt mechanisms:

  1. JWT Receipts — signed, portable tokens
  2. On-chain Receipts (optional) — anchored for added permanence

🧩 1. JWT Receipts

JWT receipts are cryptographically signed tokens (ES256, Ed25519, etc.) issued after payment.

Example: JWT Receipt Payload

{ "sub": "user:wallet:SoLWallet111...", "resource": "nft:solana:mint:9abc...xyz", "tier_id": "7d", "valid_from": "2025-10-29T00:00:00Z", "valid_until": "2025-11-05T00:00:00Z", "paid": { "amount": "2.00", "currency": "USDC", "tx": "4sJQd2cA...FyW" }, "issuer": "https://facilitator.fx402.xyz" }

Verifying a JWT Receipt

import { verifyReceipt } from "@fx402/r402"; const valid = await verifyReceipt(jwt); if (valid) console.log("✅ verified!");

Facilitator Best Practice:
Expose your public keys via /.well-known/jwks.json to enable secure, client-side JWT verification.


🧠 2. On-chain Anchors (Optional)

Receipts may optionally be anchored on-chain for added trust and permanence (e.g., via Solana Memo, IPFS).

FieldDescription
receipt_cidIPFS CID (content hash) of the signed receipt
txBlockchain transaction anchoring the hash

Anchoring allows for verification even if the facilitator goes offline.


🔐 3. Caching & Reuse Strategy

  • Cache receipts locally: (IndexedDB, Redis, files, etc.)
  • Re-use receipts until their valid_until timestamp expires.

Example: Online Receipt Validation Endpoint

GET /verify?jwt=<token>

Response:

{ "valid": true, "expires_in": 23422 }

⚙️ 4. Security Considerations

  • Always verify valid_until against server time before granting access.
  • Never trust unsigned JSON receipts in production.
  • Rotate signing keys periodically.
  • Include issuer and chain in JWT claims for auditability.

📚 Next Steps

Last updated on