Payout
What it is
A Payout lets an agent send USDC from the user's FluxA Wallet to any external address on Base. Common use cases include withdrawals, revenue splits, paying contractors, refunds, and settling off-chain obligations.
Payouts support two approval paths:
- Standard flow — the agent initiates, the user approves in the FluxA Wallet UI, and FluxA sends the transfer.
- Mandate auto-approval — if the agent passes a pre-signed
mandateIdwith sufficient budget, the payout is approved immediately with no user action.
What agents can do with it
- Send funds to any address — initiate outbound USDC transfers to any
0xaddress on Base. - Auto-approve with mandates — pass a
mandateIdto skip user approval when the mandate covers the amount. - Deduplicate by business ID — pass a
bizIdso the same external order can never create two active payouts. - Track payout status — poll the status endpoint until the payout is completed or failed (see Reading the status).
- Attach metadata — include custom metadata (order IDs, source labels) for reconciliation.
- Webhook notifications — provide a webhook URL to receive push notifications on completion.
- Idempotent retries — reuse the same
payoutIdto safely retry without duplicate transfers.
Related APIs
| Method | Endpoint | Description |
|---|---|---|
POST | /api/payouts | Create a payout request |
GET | /api/payouts/:payoutId | Get payout status |
User-side actions (approve / deny a pending payout) are performed by the user directly in the FluxA Wallet UI via the approvalUrl returned at creation; there is no public API for them.
Integration flows
There are two flows depending on whether the agent has a pre-signed budget mandate.
Flow A — with a budget mandate (auto-approval)
Use this when the agent should send payouts autonomously within a user-approved budget (e.g. recurring refunds, revenue splits, task rewards). The payout skips manual user approval and starts processing immediately.
** Your task **
Send 2.00 USDC to 0xABCD...1234 as a reward for task #42.
** Step 1 — Create a budget mandate (once, reused across payouts) **
If the agent does not already have a signed mandate that covers this
kind of payout, create one and have the user sign it:
curl -X POST https://walletapi.fluxapay.xyz/api/mandates/create-intent \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENT_JWT" \
-d '{
"intent": {
"naturalLanguage": "Pay data labeling task rewards",
"currency": "USDC",
"limitAmount": "100000000",
"validForSeconds": 2592000,
"category": "task-reward"
}
}'
The response returns:
- mandateId (e.g. "mnd_abc12345")
- authorizationUrl — surface to the user so they can sign in the
FluxA Wallet. The mandate is not usable until signed.
Poll the mandate until status is "signed":
curl https://walletapi.fluxapay.xyz/api/mandates/agent/mnd_abc12345 \
-H "Authorization: Bearer $AGENT_JWT"
** Step 2 — Create the payout with mandateId **
Pass the signed mandateId; the payout auto-approves atomically if
the remaining budget covers the amount:
curl -X POST https://walletapi.fluxapay.xyz/api/payouts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENT_JWT" \
-d '{
"payoutId": "reward-task-42",
"toAddress": "0xABCD...1234",
"amount": "2000000",
"mandateId": "mnd_abc12345",
"bizId": "task_42_reward",
"description": "Data labeling reward — task #42"
}'
Expected response:
- approvalUrl: null (already approved, no user interaction)
- mandateId: "mnd_abc12345"
If the mandate budget is insufficient, the call fails with
`mandate_insufficient_budget`; fall back to Flow B or top up the
mandate.
** Step 3 — Poll for completion **
curl https://walletapi.fluxapay.xyz/api/payouts/reward-task-42 \
-H "Authorization: Bearer $AGENT_JWT"
Read displayStatus. Keep polling while it is "processing" or
"awaiting_approval". It is done when "completed", and was not
sent when "failed", "expired", "rejected" or "canceled".
** Step 4 — Confirm **
- If completed: "Payout of 2.00 USDC sent. Tx: {txHash}"
- If failed: tell the user the payout was not sent and offer to
try again with a new payoutIdFlow B — without a mandate (user manual approval)
Use this for ad-hoc or high-value transfers where the user should review each payout individually.
** Your task **
Send 2.00 USDC to 0xABCD...1234 as a one-off withdrawal.
** Step 1 — Create the payout (no mandateId) **
curl -X POST https://walletapi.fluxapay.xyz/api/payouts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENT_JWT" \
-d '{
"payoutId": "withdraw-001",
"toAddress": "0xABCD...1234",
"amount": "2000000",
"bizId": "withdraw_001",
"description": "User withdrawal"
}'
Expected response:
- approvalUrl: "https://agentwallet.fluxapay.xyz/authorize-payout/..."
(the payout waits for the user's approval)
** Step 2 — Ask the user to approve **
Surface the approvalUrl to the user. They open it in a browser and
approve (or deny) inside the FluxA Wallet. If they deny it, or the
approval window passes, the payout fails and nothing is sent.
** Step 3 — Poll for completion **
curl https://walletapi.fluxapay.xyz/api/payouts/withdraw-001 \
-H "Authorization: Bearer $AGENT_JWT"
Read displayStatus. Keep polling while it is "processing" or
"awaiting_approval". It is done when "completed", and was not
sent when "failed", "expired", "rejected" or "canceled".
** Step 4 — Confirm **
- If completed: "Payout of 2.00 USDC sent. Tx: {txHash}"
- If failed: explain that the payout was not sent and offer to retryChoosing between the flows
- Flow A (mandate) — agent has a user-signed budget covering this payout. No user interaction; the payout starts processing immediately.
- Flow B (manual) — ad-hoc or high-value transfers. The user must approve each payout via
approvalUrlbefore anything is sent.
See Mandates for how to propose, sign, and query mandates.
Reading the status
Read displayStatus from GET /api/payouts/:payoutId:
displayStatus | What to do |
|---|---|
awaiting_approval | Remind the user of the approvalUrl |
processing | Keep polling. Don't create a second payout |
completed | Done. txHash is the on-chain transaction |
failed, expired, rejected, canceled | Nothing was sent. Tell the user; create a new payout if they still want to send |
Treat any other value as processing. Don't build logic on the lower-level status field; its values can change.
Using bizId for deduplication
When bizId is set, only one active payout can exist per user per bizId. This protects against accidental double-payment on retries. The bizId becomes available again once its payout has failed. While a payout is still processing, the bizId stays reserved.
With the CLI
# Standard: the user approves via approvalUrl
fluxa-wallet payout --to 0xABCD...1234 --amount 2000000 --id withdraw-001 --biz-id withdraw_001
# Within a signed mandate: no separate approval
fluxa-wallet payout --to 0xABCD...1234 --amount 2000000 --id reward-task-42 --mandate mnd_abc12345
fluxa-wallet payout-status --id withdraw-001See CLI › Payouts.
