Forge for FastAPI (0.7.4)
Forge adds agent traffic telemetry, x402 discovery context, and service feedback to an existing FastAPI app. It does not replace your facilitator, verify payments, or settle funds.
This release matches the Express SDK (@clawcash/forge 0.7) on the collector contract: initialization, compact feedback_id invitations, pilot and sampled feedback, wallet-linked settlement identity, OpenAPI 3.0–3.2 enrichment, and merchant feedback relay. FastAPI remains ASGI-wrapped rather than Express middleware.
The package is named clawcash-forge, imported as forge_sdk. Install from PyPI:
python -m pip install clawcash-forge==0.7.4
Integrate
Keep your FastAPI routes, lifespan, payment middleware, and facilitator registration as they are. Wrap the finished app and export that wrapper to Uvicorn:
import os
from fastapi import FastAPI
from forge_sdk import init_forge
app = FastAPI()
# Register your existing routes and middleware here.
# This includes your existing x402 v1/v2 dispatch middleware.
application = init_forge(
app,
api_key=os.environ["FORGE_API_KEY"],
agent_context=True, # False disables agent context
feedback=True, # False disables feedback
)
uvicorn server:application
app is still your FastAPI object. application is the outer ASGI app that Uvicorn serves. Do not serve server:app, which bypasses Forge. With Nginx, preserve payment-required, payment-response, and legacy x-payment-response headers. Keep ASGI lifespan enabled. For an ASGI host without lifespan, explicitly await application.start() and await application.close() in the host's lifecycle.
Create an API key for your service in Forge first. Initialization downloads only that service's registered resource routes. Non-business routes such as health checks are excluded.
What changes
- On registered x402 routes, captures status, duration, completion, agent type, client, and search query. Query strings, request bodies, and authorization/payment-signature headers are not exported wholesale.
- Captures discovery context from query parameters, JSON
agent_contextor legacy_forge(bodies up to 3 KB), andX-Agent-Context/X-Forge-Contextheaders. Runtime parsing never rejects a merchant request for missing context. - Adds
agentType,agentTypeOther,client, andsearch_queryquery declarations to GET/HEAD operations, and optionalagent_contexton eligible JSON request bodies.agentTypeandclientare required in discovery documentation. - Appends feedback guidance to existing
x-guidanceandinfo.description. OpenAPI 3.0, 3.1, and 3.2 are supported. Local response references andallOfobject schemas are copied before extension. Ambiguous/composed/external response schemas are skipped. - Adds a free
GET /feedbackquestionnaire andPOST /feedbacksubmission route on the merchant's own origin. GET without a token returns the current form; GET withtokenfetches that invitation's questionnaire. Invalid submissions explain the accepted schema so an agent can retry. - Adds only
feedback_idto eligible successful JSON objects, and advertises it in their response schema. The ID is a registered short-lived credential linked to the interaction. Pilot mode (default) invites on every eligible response.feedback_policy={"mode": "sampled", "sample_rate": 0.1}requires a wallet-linked buyer grant, matching Express. - Adds the feedback invitation to the v2
payment-requiredresource description. Recognized BazaarqueryParamsdeclarations receive context fields; existingagent_contextbody declarations receive the same required fields as Express. Unknown/custom Bazaar schema layouts are preserved, not guessed. - Reads settlement evidence from v2
payment-responseand legacyx-payment-response, and recoversscheme/asset/ amount from the requestpayment-signature(SettleResponse alone does not carry them). Challenge offers are recorded frompayment-required. A 2xx status alone is never treated as payment. Network-qualified payer addresses from successful settlement evidence support Forge's global wallet-linked agent identity via a hashedbuyer_key. - Optional
x402=resource_server(orapplication.attach_x402(server)) registers the same verify/settle observation hooks as the Express SDK, so paid calls are recorded even if a proxy strips settlement response headers.
Set feedback=False (or enable_feedback=False) to disable feedback while retaining telemetry and agent context. Set agent_context=False to disable agent context capture and its OpenAPI/x402 declarations while retaining telemetry and feedback. Both features are enabled by default and can be switched off independently. discovery=False leaves the served OpenAPI document and x402 discovery unchanged without changing context capture.
The legacy v1 challenge body is preserved byte for byte. Payment offers, recipients, assets, amounts, and opaque custom discovery fields are preserved. There is no monkey-patching of _x402_mw, _settle_v1, or facilitator functions. Do not describe this SDK as passive observation: the discovery and feedback changes above are intentional.
Custom settlement paths
If your custom v1 implementation emits a standard settlement response header, Forge can read it automatically. Otherwise report its actual outcome after settlement, inside the request task:
application.record_settlement(
success=result.success,
network="eip155:8453", # or full Solana CAIP-2 network
reference=result.transaction,
payer=result.payer,
protocol_version=1,
)
record_payment(...) accepts the same stages as Express (challenge, attempt, verification, settlement, cancellation) for custom stacks. Pass amount in base units as a string and asset address if available. Never infer payment from a request signature or HTTP 200. This is SDK-reported evidence, not independent on-chain verification. Custom background tasks outside the request context must not use these methods.
Prefer x402=resource_server when you already construct an x402ResourceServer for FastAPI payment middleware. Header observation remains the fallback and now merges accepted payment requirements from the request signature so successful settlements can enter Forge's paid ledger (scheme=exact plus network, asset, and transaction reference).
Failure and response behavior
Collector initialization failures warn and retry in the background. The merchant app remains available, but telemetry, schema enrichment, and feedback IDs are unavailable until initialization succeeds. Configuration errors (invalid collector URL, missing key, feedback route collision, invalid feedback policy) raise at construction so they can be fixed before serving.
Telemetry uses a bounded in-memory queue. It is best-effort and may drop events during prolonged outages, overload, shutdown, or worker termination. Each worker owns its own queue. No disk spool is used. application.diagnostics() reports readiness, queue depth, verification, and feedback-grant counters.
Feedback link registration can add up to 1.5 seconds to eligible JSON responses. On failure the original response is returned. Streaming responses without a bounded Content-Length, responses larger than 64 KB, compressed/signed/cacheable responses, non-object JSON, and objects already containing reserved feedback fields are not modified. Bounded JSON responses may be buffered across chunks. Merchant exceptions and disconnect cancellation propagate normally.
The feedback endpoint is free and unauthenticated at the merchant boundary. Its token and answers are validated by Forge, which applies the existing feedback rules. Use your normal edge rate limits for this public endpoint.
application = init_forge(
app,
feedback_path="/feedback",
agent_context=True, # False disables context capture and declarations
verification=True, # automatic temporary ownership proof
feedback=True, # false disables feedback route, IDs and invitations
discovery=True, # false leaves the served OpenAPI/discovery unchanged
feedback_policy={"mode": "pilot"}, # or {"mode": "sampled", "sample_rate": 0.1}
queue_size=1000,
)
FORGE_API_KEY and optional FORGE_FEEDBACK_URL are read from the environment when those arguments are omitted. No public origin is inferred from Host or forwarded headers. Relative feedback URLs stay on the merchant origin; an absolute feedback_url must be HTTPS (or explicitly enabled localhost). Mount the wrapper at your API root. Register all merchant routes and custom OpenAPI generation before wrapping.
Inspect application.diagnostics() for initialization, verification, and feedback (including grant cache counters). await application.ready() waits for the first configuration attempt. await application.shutdown() aliases close().
Framework scope
FastAPI/ASGI only, not Flask/WSGI. Express-only helpers (expressMiddleware, res.json wrapping, attachX402 on @x402/express) have ASGI equivalents above rather than the same function names. Compact feedback_id is the FastAPI invitation mode because FastAPI always serves OpenAPI; the Express legacy service_feedback URL invitation applies when that SDK is used without an OpenAPI document.
Build and test
python -m pip install -e '.[test]'
python -m pytest
python -m build
The x402 integration test additionally requires x402==2.10.0 and cdp-sdk==1.43.0. Test deployments use FastAPI 0.136.0 and Uvicorn 0.44.0, with a mock collector/facilitator and no payment. contract.json is copied from the Node SDK's feedback/context definitions to keep the collector contract aligned.
Automatic ownership verification
Enabled by default. After initialization Forge obtains a temporary proof, adds X-Forge-Verification only to configured resource responses (including unpaid 402 responses), and polls the existing ownership API every 10 seconds. The backend makes an unpaid request to the registered public resource to verify control. Nginx must preserve this response header. No payment signature, API key, or expected proof is sent in that verification request.
Proof-bearing responses use Cache-Control: private, no-store. The SDK stops attaching the header after verification completes, when the proof expires, on authorization failure, and at shutdown. Already verified services receive no proof header, including after a restart. Existing merchant headers with the same name are preserved. Temporary collector failures do not block merchant requests. Pass verification=False to disable the handshake. application.verification.status exposes initializing, pending, complete, unavailable, or disabled.
Release files for clawcash-forge 0.7.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| clawcash_forge-0.7.4.tar.gz | 223.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| clawcash_forge-0.7.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 254.5 kB
Release files / clawcash_forge-0.7.4.tar.gz
| Download URL | clawcash_forge-0.7.4.tar.gz |
|---|---|
| Size | 223.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5dab729ca6480ddfd8338495b3d8c75a3bf6d65d49baba660f426378795ee02c
|
|
BLAKE2b-256 checksum How to use checksums |
09374aece92fc731ad83aebae1019e32aeff3cddaaaf9915f1708c3afae93a39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / clawcash_forge-0.7.4-py3-none-any.whl
| Download URL | clawcash_forge-0.7.4-py3-none-any.whl |
|---|---|
| Size | 31.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
98dcb188ebae40c13c1e5866513f58911041d2d58c09010c632155e8c73783b9
|
|
BLAKE2b-256 checksum How to use checksums |
51067540c02ae3a8b927b2729e7e5a25730c57c4ca313391d9fbd446ecd48930
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|