x402sgl
v0.2.0
Published
Server-side receipt and webhook verification helpers for the x402 payment protocol
Downloads
123
Maintainers
Readme
Overview
When a buyer completes an x402 payment, the worker issues a signed receipt JWT containing the transaction details. When a seller webhook fires, the worker also signs the raw webhook body with an HMAC secret. This SDK helps you verify both layers safely.
Both the Node and Python implementations handle:
- receipt JWT verification via RS256 + JWKS
- webhook HMAC verification
- optional webhook-to-receipt cross-checking
- optional source-slug binding
Installation
Node.js
npm install x402sglconst {
verifyX402ReceiptToken,
createX402ReceiptMiddleware,
verifyX402WebhookSignature,
verifyX402WebhookEvent,
} = require('x402sgl');Python
pip install git+https://github.com/ivaavimusic/Singularity-SDK.git#subdirectory=pythonfrom x402layer_middleware import X402ReceiptVerifier, require_x402_receiptPython dependencies (installed automatically): PyJWT, cryptography. FastAPI is optional — install with pip install x402layer-sdk[fastapi].
Node.js
Receipt API
const {
verifyX402ReceiptToken,
createX402ReceiptMiddleware,
verifyX402WebhookSignature,
verifyX402WebhookEvent,
} = require('x402sgl');verifyX402ReceiptToken(token, options?)
Verifies the receipt JWT and returns the decoded claims. Throws on invalid signature, expired token, or claim mismatch.
const claims = await verifyX402ReceiptToken(token, {
requiredSourceSlug: 'my-endpoint', // optional — prevents token replay
});createX402ReceiptMiddleware(options?)
Express middleware that reads the token from X-X402-Receipt-Token or Authorization: Bearer, verifies it, and attaches the claims to req.x402Receipt.
app.get(
'/v1/resource',
createX402ReceiptMiddleware({ requiredSourceSlug: 'my-endpoint' }),
(req, res) => {
res.json({ data: '...', payer: req.x402Receipt.payer_wallet });
}
);Returns 401 if the token is missing or invalid, 403 if the source slug does not match.
Webhook API
verifyX402WebhookSignature(rawBody, signatureHeader, secret, options?)
Verifies X-X402-Signature using the shared webhook secret.
verifyX402WebhookSignature(rawBody, req.headers['x-x402-signature'], process.env.X402_WEBHOOK_SECRET)verifyX402WebhookEvent(rawBody, signatureHeader, secret, options?)
Verifies the webhook signature, parses the JSON payload, and if data.receipt_token exists, verifies the receipt too.
const { payload, receipt } = await verifyX402WebhookEvent(
rawBody,
req.headers['x-x402-signature'],
process.env.X402_WEBHOOK_SECRET,
{
requiredSourceSlug: 'claude',
requireReceipt: true,
}
)
const purchaseId = payload.data.client_reference_idIf requireReceipt: true, the helper rejects webhook payloads that do not include data.receipt_token.
Python
Receipt API
from x402layer_middleware import (
X402ReceiptVerifier,
require_x402_receipt,
verify_x402_webhook_signature,
verify_x402_webhook_event,
)X402ReceiptVerifier
verifier = X402ReceiptVerifier(
jwks_url="https://api.x402layer.cc/.well-known/jwks.json", # default
issuer="https://api.x402layer.cc", # default
audience="x402layer:receipt", # default
)require_x402_receipt(verifier, required_source_slug?)
FastAPI dependency that reads the token from X-X402-Receipt-Token or Authorization: Bearer, verifies it, and returns the decoded claims.
@app.get("/v1/resource")
async def resource(receipt=require_x402_receipt(verifier, required_source_slug="my-endpoint")):
return {"payer": receipt["payer_wallet"], "amount": receipt["amount"]}Raises HTTP 401 if the token is missing or invalid, HTTP 403 if the source slug does not match.
Webhook API
result = verify_x402_webhook_event(
raw_body,
signature_header,
secret,
verifier=X402ReceiptVerifier(),
require_receipt=True,
)
payload = result["payload"]
receipt = result["receipt"]
purchase_id = payload["data"].get("client_reference_id")verify_x402_webhook_signature(...) is also available if you only want HMAC verification.
Receipt Claims
| Claim | Type | Description |
|-------|------|-------------|
| event | string | Always "payment.succeeded" |
| source | string | "endpoint" or "product" |
| source_id | string | UUID of the paid resource |
| source_slug | string | Slug of the resource |
| amount | string | Payment amount (e.g. "1.00") |
| currency | string | Asset symbol (e.g. "USDC") |
| tx_hash | string | On-chain transaction hash |
| payer_wallet | string | Buyer wallet address |
| network | string | "base" or "solana" |
| client_reference_id | string \| null | Seller-supplied correlation id, if provided |
| metadata | object | Seller-supplied correlation metadata, if provided |
| status | string | Settlement status |
| iat | number | Issued-at (Unix timestamp) |
| exp | number | Expiry (Unix timestamp) |
| jti | string | Unique receipt ID — use for idempotency |
Token Contract
| Property | Value |
|----------|-------|
| Format | JWT (JWS) |
| Algorithm | RS256 |
| JWKS URL | https://api.x402layer.cc/.well-known/jwks.json |
| Issuer | https://api.x402layer.cc |
| Audience | x402layer:receipt |
The token is delivered in the X-X402-Receipt-Token response header after a successful payment.
Webhook Payload Contract
Seller webhook payloads are signed with:
X-X402-Signature: t=<timestamp>,v1=<hex_hmac_sha256>
The signed message is:
<timestamp>.<raw_request_body>
Current payment.succeeded payloads may include:
data.client_reference_iddata.metadatadata.receipt_tokendata.jwks_url
That makes deterministic purchase correlation possible for hosted checkout flows like:
/pay/request/claude?amount=1&client_reference_id=abc-123Security
- Always set
requiredSourceSlugin production to prevent receipt replay across resources. - Always verify the webhook signature before parsing or trusting the payload.
- If you rely on settlement authenticity, require and verify
data.receipt_token. - The SDK caches JWKS keys in memory (default 5-minute TTL) to avoid excessive network calls.
- To rotate signing keys: publish a new JWKS entry with a new
kid, then update the worker private key. Tokens signed with old keys remain verifiable until they expire.
License
MIT
