Unify Payment Link (UPL)
Resolve an agent's permanent receiving endpoint and pay via the x402 protocol. No wallet address lookup required — only the target Agent ID.
Get UPL
Request the 402 payment requirement for a target agent. The response tells you where to send funds and how much.
curl -s "https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/<agentId>?amount=<atomic_units>&asset=usdc"Path parameters
| Parameter | Type | Description |
|---|---|---|
agentId | string | The recipient agent's agent_id (required) |
Query parameters
| Parameter | Type | Description |
|---|---|---|
amount | string | Amount in atomic units (required). 1 USDC = 1000000 |
asset | string | Asset identifier (required). Only usdc is supported |
Example request
curl -s "https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=2000000&asset=usdc"Response (HTTP 402)
The server returns HTTP 402 with a JSON body following the x402 protocol format:
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "2000000",
"resource": "https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=2000000&asset=usdc",
"description": "Pay 2.00 USDC to bob-agent-id",
"payTo": "0x1234567890abcdef1234567890abcdef12345678",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2"
}
}
]
}| Field | Description |
|---|---|
x402Version | Protocol version (always 1) |
accepts[].scheme | Payment scheme (exact) |
accepts[].network | Blockchain network (base) |
accepts[].maxAmountRequired | Amount to pay in atomic units |
accepts[].resource | The full UPL URL (use this as-is for the retry) |
accepts[].description | Human-readable description |
accepts[].payTo | Recipient's current onchain wallet address |
accepts[].asset | USDC contract address on Base |
accepts[].extra.name | Token name (USD Coin) |
accepts[].extra.version | Token version (2) — used for EIP-3009 signing |
Error responses
| Status | Meaning |
|---|---|
400 | Missing amount or asset, invalid amount format, zero or negative amount, or unsupported asset |
404 | Agent not found, agent has been deleted, or agent has no wallet linked |
Error body:
{
"error": "Agent not found",
"code": "AGENT_NOT_FOUND"
}Submit payment
After obtaining the 402 payload and signing the payment via POST /api/payment/x402V3Payment, retry the same UPL URL with the X-Payment header.
curl -H "X-Payment: <xPaymentB64>" \
"https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/<agentId>?amount=<atomic_units>&asset=usdc"Headers
| Header | Description |
|---|---|
X-Payment | Base64-encoded payment proof from x402V3Payment (required) |
Example request
curl -H "X-Payment: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW..." \
"https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=2000000&asset=usdc"Response (HTTP 200)
{
"success": true,
"txHash": "0xabc123...",
"settledAmount": "2000000",
"network": "base",
"payer": "0x...",
"payee": "0x..."
}| Field | Description |
|---|---|
success | true if the onchain transfer succeeded |
txHash | Transaction hash on Base — use a block explorer to verify |
settledAmount | Amount transferred in atomic units |
network | Network where the transfer was executed |
payer | Sender's onchain address |
payee | Recipient's onchain address |
Error responses
| Status | Meaning |
|---|---|
400 | Invalid or malformed X-Payment header |
402 | Payment proof is missing, expired, or insufficient |
404 | Agent not found |
500 | Onchain transfer failed (e.g., insufficient USDC balance in the sender's wallet) |
End-to-end example
Complete flow from constructing the URL to receiving a confirmed transfer.
1. Get the 402 payload
UPL_URL="https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=1000000&asset=usdc"
PAYLOAD=$(curl -s "$UPL_URL")
echo "$PAYLOAD"
# → HTTP 402 with x402 JSON body2. Create and sign a mandate
curl -X POST https://walletapi.fluxapay.xyz/api/mandates/create-intent \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENT_JWT" \
-d '{
"intent": {
"naturalLanguage": "Transfer USDC to agents via Unify Payment Link",
"currency": "USDC",
"limitAmount": "10000000",
"validForSeconds": 2592000,
"category": "upl-transfer",
"hostAllowlist": ["walletapi.fluxapay.xyz"]
}
}'Response:
{
"status": "ok",
"mandateId": "mnd_xyz789",
"authorizationUrl": "https://agentwallet.fluxapay.xyz/mandate/mnd_xyz789",
"expiresAt": "2025-03-01T00:00:00.000Z",
"agentStatus": "ready"
}Present authorizationUrl to the user. After they sign, verify the mandate status:
curl https://walletapi.fluxapay.xyz/api/mandates/agent/mnd_xyz789 \
-H "Authorization: Bearer $AGENT_JWT"Confirm status is "signed" and isEnabled is true.
3. Sign the payment
Use the fields from the 402 payload (step 1) together with the mandate ID:
curl -X POST https://walletapi.fluxapay.xyz/api/payment/x402V3Payment \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENT_JWT" \
-d '{
"mandateId": "mnd_xyz789",
"scheme": "exact",
"network": "base",
"amount": "1000000",
"currency": "USDC",
"assetAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x1234567890abcdef1234567890abcdef12345678",
"host": "walletapi.fluxapay.xyz",
"resource": "https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=1000000&asset=usdc",
"description": "UPL transfer 1.00 USDC to bob-agent-id",
"tokenName": "USD Coin",
"tokenVersion": "2",
"validityWindowSeconds": 60
}'Response:
{
"status": "ok",
"xPaymentB64": "<base64-encoded-xPayment>",
"paymentRecordId": "..."
}4. Submit and confirm
curl -H "X-Payment: <xPaymentB64>" "$UPL_URL"Response:
{
"success": true,
"txHash": "0xabc123...",
"settledAmount": "1000000",
"network": "base",
"payer": "0x...",
"payee": "0x..."
}The transfer is confirmed onchain. Use the txHash to verify on a Base block explorer.
Notes
- Atomic units — all amounts are in USDC atomic units (6 decimals).
1000000= 1.00 USDC. - Mandate host — UPL endpoints are served from
walletapi.fluxapay.xyz. Include this host in your mandate'shostAllowlist, or omit the allowlist entirely. - Payment validity — the
xPaymentB64token expires based onvalidityWindowSeconds(default 60s). Submit it promptly after signing. - Idempotency — if the same signed payment is submitted twice, the second request will be rejected. Generate a new payment proof for each transfer.
