Create Payout
Creates one payout to your customer and reserves the funds immediately (amount + fee).
POST
/api/payout/createAuthentication
Scope: payouts:write
Authorization: Bearer <YOUR_PAYOUT_KEY>
Idempotency-Key: <unique key per attempt>
Request Parameters
| Field | Type | Description | Required |
|---|---|---|---|
amount | string | Decimal string, max 2 dp: "25.00". A JSON number is refused — floats round, and this is money | ✅ |
merchant_reference | string | Your id for this payout, ≤191 chars, permanently unique per account | ✅ |
delivery | string | link or redirect | ✅ |
currency | string | USD only, and the default | ❌ |
customer_email | string | ≤255 chars, validated | link only |
customer_id | string | ≤191 chars. Binds the payout to that customer, permanently | redirect only |
return_url | string | Must exactly match a registered origin | redirect only |
description | string | ≤255 chars. Shown to the recipient | ❌ |
case_reference | string | ≤191 chars. Your ticket id — never shown to the recipient | ❌ |
original_payment_id | string | ≤64 chars. The payment being refunded | ❌ |
You cannot supply a destination address
Sending destination or destination_address is refused with
destination_not_accepted. The recipient chooses where their own money goes, in
their own browser.
Response Fields
- 200
- 400
- 409
- 409 (unresolved)
{
"payout_id": "po_9f3c1d7b2a8e4c15d0b6a291",
"status": "awaiting_choice",
"status_version": 1,
"amount": "25.00",
"fee": "0.50",
"total_reserved": "25.50",
"currency": "USD",
"funds_released": false,
"payout_url": "https://luxfin.org/payouts/po_9f3c…/claim#claim=…",
"access_link_expires_at": "2026-10-05T09:14:22Z",
"payout_expires_at": "2026-10-05T09:14:22Z"
}
{
"error": "above_payout_limit",
"message": "maximum payout is 500.00"
}
{
"error": "insufficient_funds",
"message": "This payout needs $25.50. Your available balance is $12.40.",
"detail": { "available": "12.40", "required": "25.50", "currency": "USD" }
}
{
"operation_status": "pending",
"payout_id": null,
"error": "attempt_unresolved",
"message": "the outcome is not established; retry this attempt with the same Idempotency-Key"
}
All error codes: Limits and errors.
Behavior
payout_urlis returned once. A retry with the same key replays the same payout withpayout_url: null. Store the link when you receive it, or fetch it again with Get or rotate claim link.- Sending the link is yours to do. We do not email it. For
linkdelivery the recipient must verify the address you supplied (we email them a code) before they can choose anything. - For
redirectdelivery, send the customer's browser topayout_url— it is valid for 10 minutes, single use. - Unclaimed payouts expire at
payout_expires_at: 7 days after creation forlink, 24 hours forredirect. The money then returns to your balance. - A rejected create stays rejected for its key. Fix the cause and send it
again with a new
Idempotency-Key— see Idempotency and retries.
Request Samples
- link
- redirect
curl -X POST https://luxfin.org/api/payout/create \
-H "Authorization: Bearer $PAYOUT_KEY" \
-H "Idempotency-Key: 1e6f6a1c-2c4e-4d7e-9d0e-7a1f5c2b8f3a" \
-H "Content-Type: application/json" \
-d '{
"amount": "25.00",
"merchant_reference": "refund-ORD-10231",
"delivery": "link",
"customer_email": "person@example.com",
"description": "Refund for order ORD-10231"
}'
curl -X POST https://luxfin.org/api/payout/create \
-H "Authorization: Bearer $PAYOUT_KEY" \
-H "Idempotency-Key: 7c2d9e1a-4b3f-4a8e-b6d0-2f5e8c1a9b47" \
-H "Content-Type: application/json" \
-d '{
"amount": "25.00",
"merchant_reference": "refund-ORD-10232",
"delivery": "redirect",
"customer_id": "cust_48213",
"return_url": "https://shop.example.com/payouts/done"
}'