Refunds
Issue and manage Payment Link refunds. Refunds use the x402 reverse payment flow — the system generates a refund link, the agent/user pays the refund link using a mandate, and the funds are settled back to the original payer via the Facilitator.
All management endpoints require Authorization: Bearer <agent-jwt>.
Refund flow overview
Agent/User FluxA API Facilitator Onchain
| | | |
|-- POST initiate ------>| | |
|<-- refundUrl + plr_* --| | |
| | | |
|-- GET refundUrl ------>| | |
|<-- 402 (payTo=payer) --| | |
| | | |
|-- sign via mandate --->| | |
|-- GET + X-Payment ---->|-- verify + settle ------->|-- transfer ------>|
|<-- 200 {txHash} -------| | |- Initiate — call
POST /api/payment-links/refunds/initiatewith the originalpaymentId. The system creates apendingrefund record and returns arefundUrl. - Get 402 —
GETtherefundUrl. The server returns HTTP 402 withpayToset to the original payer's address (the refund recipient). - Sign and submit — sign the payment using a mandate and submit with
X-Paymentheader. The Facilitator verifies and settles onchain. - Done — the refund record updates to
settledand appears in the payment feed.
TIP
The payTo in a refund link points to the original payer — this is the key difference from a normal payment link where payTo is the link creator.
Initiate refund
Create a refund record and get a refund link URL.
curl -X POST https://walletapi.fluxapay.xyz/api/payment-links/refunds/initiate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{
"paymentId": 43,
"amount": "1000000",
"reason": "Customer requested refund"
}'Request fields
| Field | Type | Required | Description |
|---|---|---|---|
paymentId | number | Yes | Original payment record ID (payment_link_payments.id) |
amount | string | No | Refund amount in atomic units. Omit for full refund |
reason | string | No | Refund reason |
Response (201)
{
"refundId": "plr_abc123xyz456",
"refundUrl": "https://walletapi.fluxapay.xyz/refundlink/plr_abc123xyz456",
"paymentId": 43,
"amount": "1000000",
"currency": "USDC",
"network": "base",
"refundFrom": "0xLinkOwnerAddress",
"refundTo": "0xOriginalPayerAddress",
"refundType": "full",
"reason": "Customer requested refund",
"status": "pending",
"expiresAt": "2026-04-14T12:00:00.000Z",
"createdAt": "2026-04-13T12:00:00.000Z"
}Error responses
| Status | Description |
|---|---|
| 400 | Invalid parameters / refund amount exceeds limit / original payment not settled / payer address unknown |
| 404 | Original payment not found or not authorized |
Over-refund protection — if the requested amount exceeds the remaining refundable amount:
{
"error": "Refund amount exceeds remaining refundable amount",
"originalAmount": "5000000",
"totalRefunded": "3000000",
"remainingRefundable": "2000000",
"requestedAmount": "3000000"
}Public refund link endpoint (x402)
Public endpoint — no authentication required. The agent uses a mandate to pay this URL, which transfers funds back to the original payer.
Step 1 — Request refund payment requirements
curl -i https://walletapi.fluxapay.xyz/refundlink/plr_abc123xyz456Response (402 Payment Required):
{
"error": "Payment Required",
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"maxAmountRequired": "1000000",
"resource": "/refundlink/plr_abc123xyz456",
"description": "Refund: Customer requested refund",
"payTo": "0xOriginalPayerAddress",
"maxTimeoutSeconds": 60,
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2"
}
}
]
}WARNING
Note that payTo is the original payer's address — the refund recipient. This is the key difference from a normal payment link.
Step 2 — Submit refund payment
Sign an EIP-3009 TransferWithAuthorization using a mandate, encode as Base64, and attach as the X-Payment header.
curl -i https://walletapi.fluxapay.xyz/refundlink/plr_abc123xyz456 \
-H "X-Payment: eyJ4NDAyVmVyc2lvbiI6MSwicGF5bG9hZCI6ey..."Response (200 — success):
{
"status": "success",
"refund": {
"refundId": "plr_abc123xyz456",
"txHash": "0xRefundTxHash...",
"amount": "1000000",
"currency": "USDC",
"refundTo": "0xOriginalPayerAddress"
}
}Response (402 — payment failed):
{
"error": "Refund payment failed",
"reason": "Invalid signature"
}Response (410 — already settled or expired):
{
"error": "Refund has already been settled",
"status": "settled"
}List refunds
List all refund records for the current user.
curl https://walletapi.fluxapay.xyz/api/payment-links/refunds?limit=20&offset=0 \
-H "Authorization: Bearer $JWT_TOKEN"Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max results (max 100) |
offset | number | 0 | Pagination offset |
Response (200)
{
"refunds": [
{
"refundId": "plr_abc123xyz456",
"refundUrl": "https://walletapi.fluxapay.xyz/refundlink/plr_abc123xyz456",
"paymentId": 43,
"linkId": "pl_abc123",
"sourceType": "payment_link",
"amount": "1000000",
"currency": "USDC",
"network": "base",
"refundFrom": "0xLinkOwnerAddress",
"refundTo": "0xOriginalPayerAddress",
"status": "settled",
"refundTxHash": "0xRefundTxHash...",
"refundType": "full",
"reason": "Customer requested refund",
"originalAmount": "1000000",
"originalTxHash": "0xOriginalTxHash...",
"agentName": "My Agent",
"expiresAt": "2026-04-14T12:00:00.000Z",
"createdAt": "2026-04-13T12:00:00.000Z"
}
]
}Response fields
| Field | Type | Description |
|---|---|---|
refundId | string | Refund ID (plr_* format) |
refundUrl | string | null | Refund link URL (only returned when pending) |
paymentId | number | Original payment record ID |
linkId | string | null | Associated Payment Link ID; null for UPL |
sourceType | string | payment_link or unify_payment_link |
amount | string | Refund amount in atomic units |
currency | string | Currency |
network | string | Network |
refundFrom | string | Refund initiator address (link owner) |
refundTo | string | Refund recipient address (original payer) |
status | string | pending, settled, failed, or expired |
refundTxHash | string | null | Onchain refund transaction hash |
refundType | string | full or partial |
reason | string | null | Refund reason |
originalAmount | string | Original payment amount |
originalTxHash | string | null | Original payment tx hash |
agentName | string | null | Name of the agent that initiated the refund |
expiresAt | string | Refund link expiry (ISO 8601) |
createdAt | string | Created timestamp (ISO 8601) |
Get refund detail
Get a single refund record.
curl https://walletapi.fluxapay.xyz/api/payment-links/refunds/plr_abc123xyz456 \
-H "Authorization: Bearer $JWT_TOKEN"Response (200): same shape as a single entry in the list response.
| Status | Description |
|---|---|
| 404 | Refund not found or not authorized to view |
Cancel refund
Cancel a pending refund. Only pending refunds can be cancelled.
curl -X POST https://walletapi.fluxapay.xyz/api/payment-links/refunds/plr_abc123xyz456/cancel \
-H "Authorization: Bearer $JWT_TOKEN"Response (200):
{
"success": true,
"refundId": "plr_abc123xyz456",
"status": "cancelled"
}| Status | Description |
|---|---|
| 400 | Refund is not in pending status |
| 404 | Refund not found or not authorized |
