Unify Payment Link (UPL)
TIP
UPL is built on the x402 payment protocol. For full x402 details — including payment schemes, payload formats, and facilitator setup — see the x402 Protocol section.
What it is
A Unify Payment Link (UPL) is a permanent, public receiving endpoint that every agent gets out-of-the-box. Any sender who knows the target Agent ID can construct a UPL URL to send any amount of USDC to that agent — no wallet address required.
Every agent's UPL base address:
https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/<agentId>This base address is permanent. You can save it, share it, and reuse it for future payments. Append amount parameters when you are ready to pay.
Why use UPL
- No wallet address needed — only the target Agent ID is required. If the recipient agent changes its wallet address in the future, the UPL resolves to the new address automatically.
- No gas fees for the sender — the payment goes through the x402 protocol (EIP-3009
TransferWithAuthorization), so the transfer is executed onchain by the protocol, not by the sender. - Works across wallets — any agent or user with a FluxA Wallet and a signed mandate can pay through a UPL.
- Permanent endpoint — unlike a payment link (
pl_*) that can be deleted or expired, the UPL base URL is tied to the Agent ID and never changes.
UPL vs Payment Link
| Feature | UPL | Payment Link |
|---|---|---|
| URL lifetime | Permanent (tied to Agent ID) | Can expire or be deleted |
| Amount | Set by the sender at payment time | Fixed by the creator |
| Who creates it | Anyone — just needs the Agent ID | The recipient agent via API |
| Content delivery | No | Yes (resourceContent) |
| Use case | Agent-to-agent transfers, tipping, ad-hoc payments | Selling goods, collecting fees, invoices |
How it works
UPL leverages the x402 payment protocol. When you request a UPL URL with amount parameters, the server returns an HTTP 402 response containing the agent's current wallet address and payment requirements. You then sign an EIP-3009 TransferWithAuthorization via FluxA Wallet and submit the signed payload back — the USDC transfer is executed onchain by the protocol.
Sender FluxA Server Onchain
| | |
|-- GET UPL?amount=&asset= ------>| |
|<-- 402 {payTo, amount, ...} ----| |
| | |
|-- sign via FluxA Wallet ------->| |
|-- GET UPL + X-Payment -------->|-- execute transfer ---------->|
|<-- 200 {receipt, txHash} ------| |Detailed flow
- Construct the UPL URL with
?amount=<atomic_units>&asset=usdc. - GET the URL — the server responds with HTTP 402 and a JSON payload describing the payment requirement (recipient address, amount, asset, network).
- Create a mandate (if you don't have one already) — call
POST /api/mandates/create-intentto set a spending budget, then have your user sign it. - Sign the payment — call
POST /api/payment/x402V3Paymentwith yourmandateIdand the 402 payload fields. The server returnsxPaymentB64. - Submit the payment — retry the same UPL URL with the
X-Payment: <xPaymentB64>header. The server verifies the signature, executes the onchain transfer, and returns a 200 with the transaction receipt.
Related APIs
| Method | Endpoint | Description |
|---|---|---|
GET | /unifypaymentlink/agentid/:agentId | Get 402 payment requirement for the target agent |
GET | /unifypaymentlink/agentid/:agentId + X-Payment | Submit signed payment to complete the transfer |
POST | /api/mandates/create-intent | Create a spending mandate (budget + time window) |
GET | /api/mandates/agent/:mandateId | Check mandate status and remaining budget |
POST | /api/payment/x402V3Payment | Sign a payment using a mandate (returns xPaymentB64) |
Integration flow
Below is an example prompt you can give an AI agent to send a USDC payment to another agent via UPL.
** Your task **
Send 2.00 USDC to agent "bob-agent-id" using a Unify Payment
Link (UPL). Use the x402 V3 mandate flow so payments are
autonomous within your budget.
** Step 1 — Construct the UPL URL **
The target agent's UPL endpoint:
UPL_URL="https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=2000000&asset=usdc"
- amount is in atomic units: 2.00 USDC = 2000000
- asset must be "usdc"
** Step 2 — Get the 402 payment requirement **
curl -s "$UPL_URL"
The server returns HTTP 402 with a JSON body like:
{
"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": "0x...",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2"
}
}]
}
Save the fields from the accepts[0] object — you will need
them for the payment call.
** Step 3 — 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": "Send USDC to other agents via UPL. Budget: 10.00 USDC over 30 days.",
"currency": "USDC",
"limitAmount": "10000000",
"validForSeconds": 2592000,
"category": "upl-transfer",
"hostAllowlist": ["walletapi.fluxapay.xyz"]
}
}'
The response returns:
- mandateId (e.g. "mnd_xyz789")
- authorizationUrl (short link, TTL 10 minutes)
Ask the user to open authorizationUrl and sign the mandate.
Then verify the mandate is signed:
curl https://walletapi.fluxapay.xyz/api/mandates/agent/mnd_xyz789 \
-H "Authorization: Bearer $AGENT_JWT"
Confirm status is "signed" and isEnabled is true before
proceeding.
** Step 4 — Sign the payment via x402 V3 **
Using the 402 payload fields from Step 2 and your mandateId:
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": "2000000",
"currency": "USDC",
"assetAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "<payTo from 402 response>",
"host": "walletapi.fluxapay.xyz",
"resource": "https://walletapi.fluxapay.xyz/unifypaymentlink/agentid/bob-agent-id?amount=2000000&asset=usdc",
"description": "UPL transfer to bob-agent-id",
"tokenName": "USD Coin",
"tokenVersion": "2",
"validityWindowSeconds": 60
}'
The response includes xPaymentB64 — a base64-encoded signed
payment proof.
** Step 5 — Submit the payment **
Retry the UPL URL with the X-Payment header:
curl -H "X-Payment: <xPaymentB64>" "$UPL_URL"
A 200 response confirms the transfer was executed onchain.
The response body includes the transaction receipt and
txHash.
** Step 6 — Report **
Summarize to the user:
- Amount sent: 2.00 USDC
- Recipient: bob-agent-id
- Transaction hash
- Mandate remaining budgetMandate planning for UPL
When using UPL, your mandate's hostAllowlist should include walletapi.fluxapay.xyz since all UPL endpoints are served from this host. A single mandate can cover transfers to multiple agents — the host is the same regardless of the target Agent ID.
Sizing your mandate budget
Consider how many UPL transfers you expect to make over the mandate's validity period:
| Scenario | Suggested budget | Validity |
|---|---|---|
| Single one-off transfer of 5 USDC | 5000000 | 1 hour (3600) |
| Regular small transfers (tips, micro-payments) | 10000000 (10 USDC) | 30 days (2592000) |
| High-volume agent-to-agent settlement | 100000000 (100 USDC) | 30 days (2592000) |
WARNING
Once a mandate's budget is exhausted or expires, you must create and sign a new one. Plan ahead to avoid payment failures mid-workflow.
Error handling
UPL endpoint errors
These errors occur when curling the UPL URL (before entering the x402 flow):
| Status | Meaning | Action |
|---|---|---|
400 | Missing amount or asset, invalid amount, or unsupported asset | Check your query parameters |
404 | Agent not found, deleted, or has no wallet | Verify the Agent ID is correct |
x402 payment errors
These errors occur during the mandate / payment signing step:
| Status | status | Meaning | Action |
|---|---|---|---|
400 | mandate_required | mandateId was not provided | Include a valid mandateId |
403 | mandate_not_found | Mandate does not exist or does not belong to this agent | Check mandate ID and ownership |
403 | mandate_insufficient_budget | Remaining budget is less than the payment amount | Create a new mandate with sufficient budget |
403 | agent_not_authorized | Agent is not authorized in the user's wallet | Have the user open authorizationUrl |
See Error Codes for a full list of error codes.
Tips
- Reuse mandates — a single mandate can pay many UPL transfers as long as the budget and time window are sufficient.
- Check balance first — call
GET /api/mandates/agent/:mandateIdto seeremainingAmountbefore attempting a large transfer. - Host allowlist — if your mandate includes a
hostAllowlist, make surewalletapi.fluxapay.xyzis in the list. OmittinghostAllowlistallows any host. - Atomic units — always express amounts in atomic units. 1 USDC =
1000000(6 decimals).
