Mandates
A mandate is a spending budget that the user signs once. While it is active, the agent can pay up to the budget, inside the validity window, without asking the user each time.
All endpoints require Authorization: Bearer <agent-jwt>.
A mandate limits two things:
- Total budget (
limitAmount): the most the agent can spend under this mandate. - Validity window (
validFrom→validUntil): when the mandate can be used.
hostAllowlist and per-transaction limits are stored on the mandate for reference only. They do not restrict payments, so don't rely on them as a safety control.
Currencies
currency | Amount units | Notes |
|---|---|---|
USDC | 6 decimals (1000000 = 1 USDC) | Default. |
FLUXA_MONETIZE_CREDITS | 2 decimals (100 = 1 credit) | Credits balance. |
XRP | drops (1000000 = 1 XRP) | Only where XRP is enabled for the wallet. Otherwise you get unsupported_currency. |
CARD_USD | cents (12000 = $120.00) | Beta. Card mandates for linked-card checkout. They need extra card fields and access to the linked-card feature. |
Create intent mandate
POST/api/mandates/create-intentBearer agent-jwtCreate a mandate and get a link where the user can review and sign it.
curl -X POST https://walletapi.fluxapay.xyz/api/mandates/create-intent \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{
"intent": {
"naturalLanguage": "Pay for WHOIS API calls, up to 5 USDC this month",
"currency": "USDC",
"limitAmount": "5000000",
"validForSeconds": 2592000,
"category": "api-usage"
}
}'intent fields:
| Field | Required | Description |
|---|---|---|
naturalLanguage | Yes | Plain-language description the user sees when signing. |
limitAmount | Yes | Total budget as a positive integer string in the currency's atomic units. |
validForSeconds | Yes | How long the mandate is valid, counted from creation. Must be a positive integer of at most 31536000 (1 year). For CARD_USD it defaults to 3600. validUntil is not accepted. |
currency | No | See Currencies. Defaults to USDC. |
category | No | Your own label for grouping. |
hostAllowlist | No | Stored for reference only. Not enforced. |
Response (200):
{
"status": "ok",
"mandateId": "mand_Q2h8x0b1Yc3k9ZpLmN4rTw",
"authorizationUrl": "https://agentwallet.fluxapay.xyz/onboard/intent?oid=oi_...",
"expiresAt": "2026-10-27T18:00:00.000Z",
"agentStatus": "ready"
}| Field | Description |
|---|---|
mandateId | Mandate ID (mand_…). |
authorizationUrl | Link for the user. On one page they link the agent to their wallet (if needed) and sign the mandate. |
expiresAt | When authorizationUrl stops working (about 6 hours). This is not the mandate's validity end. After this time, use the mandate's signUrl from Get mandate by ID, or create a new mandate. |
agentStatus | ready if the agent is already linked to the user's wallet, or needs_wallet_authorization if the user must link it first (the same authorizationUrl handles this). |
Show authorizationUrl to the user. Then poll Get mandate by ID until status is signed.
Errors ({ "status": "error", "code", "message" }):
| HTTP | code | When |
|---|---|---|
| 400 | missing_natural_language | intent.naturalLanguage is missing. |
| 400 | unsupported_currency | The currency isn't supported or isn't enabled. |
| 400 | invalid_limit_amount | limitAmount isn't a positive integer string. |
| 400 | invalid_valid_for_seconds | validForSeconds is missing, not a positive integer, or over 1 year. |
| 400 | valid_until_not_supported | You sent validUntil. Use validForSeconds. |
| 401 | agent_auth_failed | The agent JWT is missing, invalid or expired. A VC token returns { "error": "wrong_token_type" }. |
Mandate status
status | Meaning | Usable for payments? |
|---|---|---|
pending_signature | Awaiting the user's signature. | No. Send the user to signUrl / approvalUrl. |
signed | Signed by the user. | Yes, if it is also enabled, inside its validity window and has budget left. |
| any other value | No longer usable (for example revoked or expired). | No. Create a new mandate. |
validUntil passing does not always change status. Always check the validity window yourself, or use Get eligible mandates, which only returns usable mandates.
Get eligible mandates
GET/api/mandates/eligibleBearer agent-jwtFind the agent's mandates that can pay a given amount right now. The results are signed, enabled, inside their window, in the requested currency, and have at least amount remaining. Use this before calling x402 V3 to pick a mandateId.
curl -G https://walletapi.fluxapay.xyz/api/mandates/eligible \
-H "Authorization: Bearer $JWT_TOKEN" \
--data-urlencode "host=x402whois.com" \
--data-urlencode "amount=10000" \
--data-urlencode "currency=USDC"Query parameters:
| Param | Required | Description |
|---|---|---|
host | Yes | Host you are paying. It is echoed back in criteria but doesn't filter results. |
amount | Yes | Payment amount in atomic units. |
currency | No | See Currencies. Defaults to USDC. |
Response:
{
"status": "ok",
"criteria": { "host": "x402whois.com", "amount": "10000", "currency": "USDC" },
"eligibleMandates": [
{
"mandateId": "mand_Q2h8x0b1Yc3k9ZpLmN4rTw",
"status": "signed",
"isEnabled": true,
"naturalLanguage": "Pay for WHOIS API calls, up to 5 USDC this month",
"category": "api-usage",
"currency": "USDC",
"limitAmount": "5000000",
"spentAmount": "100000",
"pendingSpentAmount": "0",
"remainingAmount": "4900000",
"validFrom": "2026-10-01T00:00:00.000Z",
"validUntil": "2026-10-31T00:00:00.000Z",
"signedAt": "2026-10-01T00:05:00.000Z",
"createdAt": "2026-10-01T00:00:00.000Z",
"updatedAt": "2026-10-20T08:00:00.000Z",
"detailsUrl": "https://agentwallet.fluxapay.xyz/mandates/mand_Q2h8x0b1Yc3k9ZpLmN4rTw",
"signUrl": "https://agentwallet.fluxapay.xyz/onboard/intent?mandateId=mand_Q2h8x0b1Yc3k9ZpLmN4rTw"
}
]
}Results are ordered so that the mandate expiring soonest comes first. An empty eligibleMandates array means no mandate can cover this payment. Create a new mandate, or fall back to x402 V1.
remainingAmount = limitAmount − spentAmount − pendingSpentAmount. pendingSpentAmount is budget held by payments that haven't finished yet.
Errors:
| HTTP | code | When |
|---|---|---|
| 400 | missing_host / invalid_amount / unsupported_currency | Invalid query parameters. |
| 401 | agent_auth_failed | Invalid agent JWT. |
| 403 / 404 | agent_not_authorized | The agent isn't linked to an authorized FluxA Wallet. |
List agent mandates
GET/api/mandatesBearer agent-jwtList the agent's mandates (up to 200, newest first), whatever their status.
curl https://walletapi.fluxapay.xyz/api/mandates \
-H "Authorization: Bearer $JWT_TOKEN"Response:
{
"status": "ok",
"mandates": [
{
"mandateId": "mand_Q2h8x0b1Yc3k9ZpLmN4rTw",
"status": "signed",
"isEnabled": true,
"naturalLanguage": "Pay for WHOIS API calls, up to 5 USDC this month",
"category": "api-usage",
"currency": "USDC",
"limitAmount": "5000000",
"spentAmount": "100000",
"pendingSpentAmount": "0",
"remainingAmount": "4900000",
"validFrom": "2026-10-01T00:00:00.000Z",
"validUntil": "2026-10-31T00:00:00.000Z",
"signedAt": "2026-10-01T00:05:00.000Z",
"createdAt": "2026-10-01T00:00:00.000Z",
"updatedAt": "2026-10-20T08:00:00.000Z"
}
]
}A 200 response also tells you the agent is linked to an authorized wallet. A 403 with agent_not_authorized means it isn't linked yet.
Get mandate by ID
GET/api/mandates/agent/:mandateIdBearer agent-jwtGet one mandate, including its live remaining budget. The mandate is wrapped in a mandate object.
curl https://walletapi.fluxapay.xyz/api/mandates/agent/mand_Q2h8x0b1Yc3k9ZpLmN4rTw \
-H "Authorization: Bearer $JWT_TOKEN"{
"status": "ok",
"mandate": {
"mandateId": "mand_Q2h8x0b1Yc3k9ZpLmN4rTw",
"status": "signed",
"naturalLanguage": "Pay for WHOIS API calls, up to 5 USDC this month",
"category": "api-usage",
"currency": "USDC",
"limitAmount": "5000000",
"spentAmount": "100000",
"pendingSpentAmount": "0",
"remainingAmount": "4900000",
"validFrom": "2026-10-01T00:00:00.000Z",
"validUntil": "2026-10-31T00:00:00.000Z",
"signedAt": "2026-10-01T00:05:00.000Z",
"createdAt": "2026-10-01T00:00:00.000Z",
"updatedAt": "2026-10-20T08:00:00.000Z",
"signUrl": "https://agentwallet.fluxapay.xyz/onboard/intent?mandateId=mand_Q2h8x0b1Yc3k9ZpLmN4rTw"
}
}This response has no isEnabled field. To check that a mandate can actually pay now, use Get eligible mandates. signUrl stays valid while the mandate is awaiting signature, so use it after the original authorizationUrl has expired.
CARD_USD mandates (Beta) return a card-specific shape that includes the merchant and card execution details.
Errors:
| HTTP | code | When |
|---|---|---|
| 401 | agent_auth_failed | Invalid agent JWT. |
| 403 | agent_not_authorized | The agent isn't linked to an authorized FluxA Wallet. |
| 404 | mandate_not_found | No such mandate for this agent. |
