AttestSeal trust attestation headers for x402 / AP2 / MPP payment protocols. Drop-in middleware for FastAPI/Flask/aiohttp servers and a verifier for httpx/aiohttp clients.
Project description
attestseal-x402
AttestSeal trust attestation headers for x402, AP2, and MPP payment protocols. Drop-in middleware for FastAPI, Flask, and aiohttp servers, plus a verifier for httpx and aiohttp clients.
This is the reference implementation of the X-AttestSeal-* HTTP Header Specification.
Install
pip install attestseal-x402
Optional extras for framework-specific helpers:
pip install 'attestseal-x402[fastapi]'
pip install 'attestseal-x402[flask]'
pip install 'attestseal-x402[aiohttp]'
Server: stamp X-AttestSeal-* on your 402 responses
FastAPI / Starlette:
from fastapi import FastAPI, Response
from attestseal_x402.server import asgi_middleware, AttestationFetcher
app = FastAPI()
fetcher = AttestationFetcher() # 24h cache by default
app.add_middleware(asgi_middleware, domain="merchant.example", fetcher=fetcher)
@app.get("/paid-resource")
def paid_resource():
return Response(
status_code=402,
content='{"scheme":"x402","amount":"0.10","currency":"USD"}',
media_type="application/json",
headers={"Accept-Payment": "x402; scheme=base-usdc; amount=0.10"},
)
Flask:
from flask import Flask, jsonify
from attestseal_x402.server import flask_after_request
app = Flask(__name__)
app.after_request(flask_after_request("merchant.example"))
@app.get("/paid-resource")
def paid_resource():
body = jsonify(scheme="x402", amount="0.10", currency="USD")
body.status_code = 402
body.headers["Accept-Payment"] = "x402; scheme=base-usdc; amount=0.10"
return body
The middleware fetches your domain's attestation from
https://api.attestseal.com/v1/check/<domain> once per cache TTL (default
24 hours) and stamps the headers on every 402 response.
Client: verify before paying
import httpx
from attestseal_x402 import AttestationVerifier
verifier = AttestationVerifier(allowed_issuers={"did:web:attestseal.com"})
resp = httpx.get("https://merchant.example/paid-resource")
if resp.status_code == 402:
result = verifier.verify_response_headers(
resp.headers, request_url=str(resp.url),
)
if result.ok:
# Apply policy keyed on assuranceBasis
if result.attestation.assurance_basis == "well_known_tranco_anchor":
pay(result.attestation, limit=5.00)
elif result.attestation.assurance_basis == "kyc_verified":
pay(result.attestation, limit=None)
elif result.attestation.assurance_basis in {"tracking", "not_recommended"}:
refuse()
else:
ask_user(result.attestation)
else:
# Verification failed; fall back to the AttestSeal API for a fresh check
fallback_check(resp.url)
Reasons that come back as result.reason when verification fails:
missing_required_header, domain_mismatch, expired, issuer_not_allowed,
did_resolution_failed, key_not_found, bad_signature. Fall-back-to-API is
the recommended response for everything except domain_mismatch and
bad_signature, which suggest active tampering.
Architecture
attestseal_x402/
attestation.py -- Attestation dataclass + canonical signing form (SHA-256 over sorted-keys JSON)
headers.py -- X-AttestSeal-* names + (de)serialization
did_resolver.py -- did:web fetch + 24h TTL cache + Ed25519 key extraction
client.py -- AttestationVerifier (one entrypoint: verify_response_headers)
server.py -- AttestationFetcher + ASGI middleware + Flask hook
The same canonical signing form is used by the production AttestSeal API,
so attestations issued by did:web:attestseal.com verify with this client.
Testing
pip install 'attestseal-x402[test]'
pytest tests/
The test suite covers signing-form stability across header round-trips, signature tampering detection, expiry, issuer allow-listing, and domain-mismatch rejection.
Spec compatibility
This package implements X-AttestSeal-* spec version 0.1.0. See
spec/X-ATTESTSEAL-HEADERS.md in the main repo for the full protocol
document. Compatibility is maintained across patch and minor versions of
the spec; major version changes (signing form, required headers) will be
published as attestseal-x402 major version bumps.
License
MIT. See LICENSE in the package root.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file attestseal_x402-0.1.0.tar.gz.
File metadata
- Download URL: attestseal_x402-0.1.0.tar.gz
- Upload date:
- Size: 17.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
857da504a60c715a0db72084ce196367bc206ca81577a1fdb95f38fc4980df93
|
|
| MD5 |
14f6ee519789b6f1889c742fde270cdc
|
|
| BLAKE2b-256 |
293d07776cc272e5630ee11350c21e875bac1f43b720bf99dcc72768028b13d6
|
File details
Details for the file attestseal_x402-0.1.0-py3-none-any.whl.
File metadata
- Download URL: attestseal_x402-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49a74644e0a8cc116e26b77636f01e0691a6fc76f2b9553d841990c9e2e6af4c
|
|
| MD5 |
855825a95c453d4b108c05aa169c6434
|
|
| BLAKE2b-256 |
752fa2bed7ae678f2f52eb04fc020a85e49a8fe67ed2b4d44af679e1bb50fa46
|