x402 Support
Dhali supports the x402 standard for HTTP-based payments. This allows for a standardized way to handle payments and resource discovery in a machine-to-machine economy.
Overview
The x402 protocol provides a way for resource servers to:
- Advertise payment requirements via standard HTTP headers.
- Verify payments through a facilitator.
- Standardize pricing across different networks and assets.
Resource Server Example (Python)
Below is a complete example of an x402 resource server built with FastAPI. This server uses the x402 middleware to handle payment verification automatically.
Setup
You will need the x402 and fastapi Python packages:
pip install x402 fastapi
Implementation
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import json
import x402.http as x402_http
from x402 import AssetAmount, Network, PaymentRequirements, Price, SupportedKind, x402ResourceServer
from x402.http.middleware import fastapi_payment_middleware
from x402.schemas import FacilitatorConfig
class DhaliSchemeNetworkServer:
@property
def scheme(self) -> str:
return "dhali"
def parse_price(self, price: Price, network: Network) -> AssetAmount:
return price
def enhance_payment_requirements(self, requirements: PaymentRequirements, supported_kind: SupportedKind, extensions: list[str]) -> PaymentRequirements:
return requirements
class DhaliPaywallProvider:
def generate_html(self, payment_required, config=None):
return json.dumps(accepts)
facilitator_url = "https://x402.api.dhali.io/v2/..."
accepts = {"scheme":"dhali","network": ...}
dhali_schema = DhaliSchemeNetworkServer()
app = FastAPI(title="Dhali Paid Resource")
facilitator = x402_http.HTTPFacilitatorClient(FacilitatorConfig(url=facilitator_url))
x402_server = x402ResourceServer(facilitator)
x402_server.register(accepts["network"], dhali_schema)
routes = {
"GET /*": {
"accepts": [accepts],
},
}
@app.middleware("http")
async def x402_middleware(request, call_next):
return await fastapi_payment_middleware(routes=routes, server=x402_server, paywall_config=None, paywall_provider=DhaliPaywallProvider())(request, call_next)
@app.get("/data")
async def get_paid_data(request: Request):
return JSONResponse({"message": "Here is your paid data"})
How to use
1. Get your facilitator and accepts payload
Navigate to Dhali Portal, link your wallet, and create a new asset. Then, go to your new asset's dashboard page and copy your x402 address and accepts payload into the variables facilitator_url and accepts above.
2. Spin up the above server
After following the above prerequisite, save the implementation example above as main.py and run it using uvicorn:
uvicorn main:app --reload --port 8001
Your server will be running at http://127.0.0.1:8001.
3. Create an x402 payment signature
To access the /data endpoint, you need a valid payment signature.
-
Get the
payment-requiredheader from your server. You will need this to build the x402payment-signatureheader in the next steps:curl -v http://127.0.0.1:8001/dataYou should see the
payment-requiredheader in the output. -
Navigate to the Dhali Payment Terminal, or use our Python or JavaScript libraries. Deposit sufficient funds into your payment channel and create a payment signature (ensure you use the correct currency and network as defined in your API's dashboard).
- Once the payment is created, copy the x402 payment signature (this is a base64 encoded payload).
4. Send a request with the signature
Use curl to send a request to your local server, including the signature in the payment-signature header:
curl -v -H "payment-signature: <your_copied_signature>" http://127.0.0.1:8001/data
If the signature is valid, your server will respond with:
{"message": "Here is your paid data"}
Tip (Debugging failed requests):
If the request fails (e.g. you receive another 402), inspect the returned payment-required header. This header is base64-encoded — decode it to see the facilitator’s structured error:
echo "<payment-required-header>" | base64 -d | jq
This often reveals issues such as wrong network, asset mismatch, insufficient channel balance, or an expired claim.