Card payouts
A payout sends money from your MAXFI balance to a person’s bank card. One API serves all payout methods — /v2/payouts — and the method field selects the method. Today there is one method: "card". Payouts use the same secret keys as payments (sk_live_…, sk_test_…) and the same webhook URL and signature.
403 card_payouts_not_enabled. Test mode (sk_test_…) works for every account. To enable live payouts, contact MAXFI.How it works
- Your server creates a payout:
POST /v2/payoutswith"method": "card", an amount and a currency. The response has"status": "pending"and apayout_url. - You send
payout_urlto the recipient, for example by email or in your app. - The recipient opens the link and enters the card number and the name on the card on a MAXFI page. The page shows the amount and the name of your business. The card number never passes through your systems.
- MAXFI sends the transfer to the bank (
payout.processing) and then reports the result:payout.succeededorpayout.failed.
If the recipient does not enter a card before expires_at, the payout becomes expired. The link is valid for 24 hours unless your account has a different setting; expires_in changes it for one payout (in seconds, from 15 minutes to 7 days). While a payout is pending, you can cancel it.
1. Create a payout
Send method, amount in minor units (1500 = 15.00) and currency — card payouts accept only AZN. Optional fields: reference (your payout ID), description, metadata and expires_in. All fields and errors are in the API reference.
curl https://maxfi-api.exezine.az/v2/payouts \ -H "Authorization: Bearer $MAXFI_SECRET_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: payout-order-1042" \ -d '{ "method": "card", "amount": 1500, "currency": "AZN", "reference": "order-1042", "description": "Payout for order 1042", "metadata": { "order_id": "1042" } }'
The response is 201 with the payout. Send payout_url to the recipient: the field is filled while the payout is pending and is null afterwards.
{
"id": "po_3f9c2a7b1d4e5f60718293ab",
"object": "payout",
"method": "card",
"status": "pending",
"amount": 1500,
"currency": "AZN",
"description": "Payout for order 1042",
"reference": "order-1042",
"metadata": { "order_id": "1042" },
"payout_url": "https://maxfi-api.exezine.az/payout/<token>",
"expires_at": "2026-11-14T12:00:00.000Z",
"card": null,
"recipient": null,
"failure_code": null,
"failure_message": null,
"livemode": false,
"created_at": "2026-11-13T12:00:00.000Z",
"completed_at": null
}2. Follow and cancel
Webhooks tell you when the status changes. You can also read a payout with GET /v2/payouts/{id} or list payouts with GET /v2/payouts. To cancel a payout before the recipient enters a card, call POST /v2/payouts/{id}/cancel; after that the recipient can no longer enter a card.
# Read one payout curl https://maxfi-api.exezine.az/v2/payouts/po_3f9c2a7b1d4e5f60718293ab \ -H "Authorization: Bearer $MAXFI_SECRET_KEY" # Payouts that are still waiting for the recipient, newest first curl "https://maxfi-api.exezine.az/v2/payouts?status=pending&limit=20" \ -H "Authorization: Bearer $MAXFI_SECRET_KEY" # Cancel a payout while it is pending curl -X POST https://maxfi-api.exezine.az/v2/payouts/po_3f9c2a7b1d4e5f60718293ab/cancel \ -H "Authorization: Bearer $MAXFI_SECRET_KEY"
Money and limits
- In live mode, creating a payout holds the amount on your available balance. The hold is charged when the payout succeeds and released when it fails, is canceled or expires.
- If your available balance does not cover the payout, the API answers
402 insufficient_balanceand holds nothing. You can retry later with the samereference. - MAXFI sets limits for your account: the maximum amount of one payout (
400 amount_too_large), and the number and total amount of payouts per day (400 daily_count_exceeded,400 daily_amount_exceeded). Daily limits apply in live mode only. - In live mode, MAXFI screens every recipient before the transfer. A payout declined by this check fails with
payout_declined; MAXFI does not disclose the reason. - The bank can return a transfer after it succeeded: the payout then becomes
reversed. The returned amount is not added back to your balance automatically — contact MAXFI support.
Statuses
| Status | Meaning | Webhook event |
|---|---|---|
| pending | Waiting for the recipient to enter a card. payout_url is filled only in this status. | — |
| processing | The recipient entered a card and MAXFI sent the transfer to the bank. The result is not known yet. | payout.processing |
| succeeded | The transfer succeeded: the money was sent to the recipient’s card. | payout.succeeded |
| failed | The transfer did not go through. See failure_code. | payout.failed |
| canceled | You canceled the payout before the recipient entered a card. | payout.canceled |
| expired | The link expired before the recipient entered a card. | payout.expired |
| reversed | The bank returned the transfer after it had succeeded. | payout.reversed |
Failure codes
failure_code and failure_message are filled when the status is failed, canceled or expired. failure_message is a short explanation in English.
| Code | Meaning |
|---|---|
| card_declined | The card issuer declined the transfer. |
| expired_card | The card has expired. |
| insufficient_balance | Your available balance did not cover the payout (live mode). |
| payout_declined | MAXFI declined the payout after checking the recipient. No details are given. |
| processing_error | The payout could not be processed. |
| link_expired | The recipient did not enter a card before the link expired (status expired). |
| canceled | You canceled the payout (status canceled). |
| test_card_required | Test mode accepts only test cards. |
Webhooks
- MAXFI sends
payout.processing,payout.succeeded,payout.failed,payout.canceled,payout.expiredandpayout.reversedto the same webhook URL as payment events and signs them the same way.dataholds the payout object withoutpayout_url. - Select the payout events in the merchant portal under Developer Hub → Webhooks: events that are not selected are not sent.
- Each event type is queued at most once per payout. A delivery can still be repeated, for example after a timeout, so skip event IDs you have already processed. See Webhooks.
Test mode
With a test key (sk_test_…) payouts never reach a bank and do not touch your balance, and they carry "livemode": false. Open payout_url and enter one of these cards with any name made of letters, for example “Test Recipient”.
| Card | Result |
|---|---|
| 4242 4242 4242 4242 | Success. |
| 5555 5555 5555 4444 | Success. |
| 4000 0000 0000 0002 | Declined: card_declined. |
| 4000 0000 0000 0069 | Expired card: expired_card. |
| 4000 0000 0000 0119 | Stays processing, then succeeds — at least 20 seconds later, usually within two minutes. |
| 4000 0000 0000 0259 | The connection is lost: the payout stays processing, then fails with card_declined — at least 20 seconds later, usually within two minutes. |
- Any other card is rejected in test mode: the page shows an error and the payout stays
pending. - Daily limits do not apply in test mode; the limit for one payout does.
Security
- payout_url works like a key. Whoever opens it can direct the payout to their own card. Send it only to the intended recipient, over a channel you trust. Webhook events do not include it.
- The API does not accept card numbers:
POST /v2/payoutsrejects unknown fields with400 VALIDATION_ERROR. After the recipient enters a card you get only its first 6 and last 4 digits (card.bin,card.last4) and the name on the card (recipient.name). - Make retries safe. A repeat with the same
reference, amount and currency returns the existing payout instead of creating a second one; different parameters get409 reference_already_used.POST /v2/payoutsandPOST /v2/payouts/{id}/cancelalso accept theIdempotency-Keyheader — see the API conventions.
