HTTP 402 Paywall
Amrood supports an x402-style payment protocol over HTTP — any API can charge per-call in INR, and AI agents with Amrood wallets can pay automatically. This brings the machine-to-machine payment model of x402 to fiat currency.
How It Works
Step by step
- Agent makes a normal HTTP request to an API endpoint
- Server returns HTTP 402 Payment Required with an
X-AMROOD-PAY header containing payment instructions (amount, payee, nonce)
- Agent pays the specified payee via Amrood’s
POST /v1/agents/{id}/pay endpoint, using the nonce as the payment reference
- Amrood returns a transaction ID
- Agent retries the original request with an
X-AMROOD-PAYMENT header containing the transaction proof
- Server verifies the payment via Amrood’s verification endpoint
- Amrood confirms the payment is valid
- Server returns the requested resource
For API Developers (Server Side)
Install the amrood-paywall package:
pip install amrood-paywall
Add a one-line decorator to any FastAPI endpoint:
from fastapi import FastAPI, Request
from amrood_paywall import amrood_pay
app = FastAPI()
@app.get("/api/premium-data")
@amrood_pay(amount="5.00", pay_to="databot")
async def get_premium_data(request: Request):
return {"data": "premium content worth paying for"}
Set the AMROOD_AGENT_KEY environment variable to your agent’s API key so the server can verify incoming payments.
How the decorator works
- On first request (no payment proof), returns HTTP 402 with:
X-AMROOD-PAY: base64({ "payTo": "databot", "amount": "5.00", "asset": "INR", "nonce": "uuid" })
- On retry with
X-AMROOD-PAYMENT header, verifies the payment via GET /v1/transactions/{txn_id}/verify
- If verified, passes the request through to your endpoint
- Nonces are tracked to prevent replay attacks (one payment = one access)
Configuration
@amrood_pay(
amount="10.00", # Amount in INR
pay_to="myagent", # Your agent handle or ID
)
| Environment Variable | Description |
|---|
AMROOD_AGENT_KEY | Your agent’s API key (required for payment verification) |
AMROOD_API_URL | API base URL (default: https://api.amrood.io) |
For AI Agents (Client Side)
The amrood_http_pay tool handles the entire 402 flow automatically:
> Fetch data from https://api.example.com/premium-data
Claude: The API requires payment of ₹5.00 to @databot.
Paid ₹5.00 automatically. Here's the data: { ... }
Using the API directly
If you’re building a custom client:
import httpx, json, base64
# Step 1: Make the request
resp = httpx.get("https://api.example.com/premium-data")
if resp.status_code == 402:
# Step 2: Parse payment instructions
pay_header = resp.headers["x-amrood-pay"]
instructions = json.loads(base64.b64decode(pay_header))
# { "payTo": "databot", "amount": "5.00", "asset": "INR", "nonce": "uuid" }
# Step 3: Pay via Amrood
pay_resp = httpx.post(
f"https://api.amrood.io/v1/agents/{agent_id}/pay",
headers={"x-agent-key": agent_key},
json={
"to": instructions["payTo"],
"amount": float(instructions["amount"]),
"reference": instructions["nonce"],
},
)
txn_id = pay_resp.json()["payment_id"]
# Step 4: Retry with payment proof
proof = base64.b64encode(json.dumps({
"version": 1,
"transactionId": txn_id,
"fromAgent": agent_id,
"nonce": instructions["nonce"],
}).encode()).decode()
result = httpx.get(
"https://api.example.com/premium-data",
headers={"x-amrood-payment": proof},
)
print(result.json())
Transaction Verification API
The verification endpoint allows API servers to confirm that a payment was made:
GET /v1/transactions/{txn_id}/verify?expected_payee=databot&expected_amount=5.00&nonce=uuid
Headers:
x-agent-key: agk_live_xxx (payee's agent key)
Response:
{
"verified": true,
"transaction_id": "pay_abc123",
"from": "clientbot",
"to": "databot",
"amount": "5.00",
"asset": "INR",
"created_at": "2025-06-15T10:30:00Z"
}
The calling agent must be the payee (recipient) of the transaction. This prevents unauthorized balance snooping.
Verification checks
| Check | Failure Reason |
|---|
| Transaction exists | transaction_not_found |
| Transaction is completed | transaction_not_completed |
| Caller is the payee | not_payee |
| Payee matches expected | payee_mismatch |
| Amount is sufficient | insufficient_amount |
| Nonce matches reference | nonce_mismatch |
X-AMROOD-PAY (Server → Client)
Sent with HTTP 402 responses. Base64-encoded JSON:
{
"payTo": "databot",
"amount": "5.00",
"asset": "INR",
"nonce": "550e8400-e29b-41d4-a716-446655440000"
}
X-AMROOD-PAYMENT (Client → Server)
Sent on retry after payment. Base64-encoded JSON:
{
"version": 1,
"transactionId": "pay_abc123",
"fromAgent": "agt_clientbot",
"nonce": "550e8400-e29b-41d4-a716-446655440000"
}
Security
- Nonce replay protection — each nonce can only be used once. The server tracks used nonces with a TTL.
- Payee-only verification — only the payee can call the verify endpoint, preventing unauthorized transaction lookups.
- Amount validation — the verify endpoint checks that the paid amount meets or exceeds the expected amount.
- Standard Amrood policies apply — spend limits, allowed payees, and all other guardrails are enforced on the underlying payment.
Links