> ## Documentation Index
> Fetch the complete documentation index at: https://docs.platnova.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Payouts

> Pay out to Nigerian bank accounts by your own reference, one at a time or in bulk, with a name check before anything is sent.

## Send a payout

`POST /v1/partner/payouts` (needs an `Idempotency-Key`)

```bash theme={null}
curl -X POST https://api.platnova.com/v1/partner/payouts \
  -H "X-API-Key: $PLATNOVA_API_KEY" \
  -H "Idempotency-Key: 6f1c2b7e-payout-123" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_reference": "SL-PAYOUT-123",
    "from_amount": 50000,
    "from_wallet_id": "<your NGN wallet id>",
    "to_currency": "NGN",
    "payment_method": "bank_transfer",
    "info": {
      "account_number": "0123456789",
      "bank_code": "058",
      "account_name": "Ada Obi",
      "narration": "Booking 123"
    }
  }'
```

The body is the same as `POST /v1/payments/send`, plus `partner_reference`. Partner payouts are same-currency and immediate. A scheduled or recurring payout is refused with `422` `partner_payout_immediate_only`.

> [!NOTE]
>
> An API-key send through `/v1/payments/send` from a partner business meets the same limits and the same name check, and needs an `Idempotency-Key` there too.

## The name check

Before anything is sent, we ask the bank whose account it is and compare that name with `info.account_name`:

| Result | Meaning |
| - | - |
| `exact` | The same words, in any order and any case. |
| `close` | The shorter name has at least two words and all of them are in the longer one, or the two names share at least two words. |
| `mismatch` | The names do not agree. |
| `unverified` | No `account_name` was sent, or the bank could not be reached. |

With name matching on (the default), `mismatch` is refused with `422` `name_mismatch` and `unverified` with `422` `name_unverified`. **Nothing is sent** in either case.

## The answer

```json theme={null}
{
  "partner_reference": "SL-PAYOUT-123",
  "status": "created",
  "transaction_ref": "TRX…",
  "transfer_status": "pending",
  "amount": 50000,
  "currency": "NGN",
  "name_check": { "result": "exact", "expected_name": "Ada Obi", "resolved_name": "OBI ADA" }
}
```

`status` is one of:

* `created`: the payout is on its way.
* `refused`: a refusal has the same shape, with `error: {code, message, fields}`.
* `unknown`: the bank's answer was lost (`provider_unconfirmed`). Read the payout before sending again.

The outcome arrives as the `payout.succeeded`, `payout.failed` or `payout.reversed` [webhook](/partners/webhooks.md).

## Fees: never below what the transfer costs

A partner payout is never charged less than it costs Platnova to send. Your normal fee for the amount applies. **If that fee is below the transfer's cost, it is raised** to the greater of:

* the cost plus 3%;
* the cost plus ₦50.

VAT is then charged on the raised fee.

| Rail | Cost per transfer |
| - | - |
| PalmPay | ₦100 |
| Paga | ₦107.50 |
| Any other, or not yet known | ₦107.50 |

For example, a ₦3,000 payout routed through PalmPay would normally cost ₦25 + ₦1.87 VAT. It is charged **₦150 + ₦11.25 VAT**. The rail is chosen by Platnova per corridor. If the rail isn't known when the payout is priced, the dearest cost is used.

This applies to every payout made with your API key: `/v1/partner/payouts`, each item of `/payouts/bulk`, and `/v1/payments/send`. Your wallet must hold the amount plus the raised fee and VAT. If it doesn't, the payout is refused `insufficient funds` and nothing is sent.

**Where you see it:** the fee and VAT actually charged are on the payout's transaction: `fee`, and the `charges` breakdown on `GET /v1/transactions/{id}`. The payout webhooks carry the fee too, as `data.fee` (VAT not included).

> [!WARNING]
>
> `POST /v1/payments/quote` does **not** apply the minimum yet. For a small payout it can show a lower fee than the one charged. Until that is fixed, work out the fee as max(normal fee, cost + 3%, cost + ₦50), plus VAT, or read it from the transaction after sending.

## Bulk payouts

`POST /v1/partner/payouts/bulk` (needs an `Idempotency-Key`) with `{ "items": [ <payout body>, … ] }`.

* A request takes at most 50 items.
* Each item needs its own `partner_reference`. A duplicate within one request is refused with `400`.
* Items run in order. Each item is idempotent on its own reference, so resending a bulk request that timed out is safe: items that already ran return their first result.

The answer is `{ "items": [ <result>, … ], "created": 48, "not_created": 2 }`.

## Read a payout

`GET /v1/partner/payouts/{partner_reference}`

```json theme={null}
{
  "partner_reference": "SL-PAYOUT-123",
  "kind": "payout",
  "status": "succeeded",
  "object_ref": "TRX…",
  "amount": 50000,
  "currency": "NGN",
  "result": { "…": "the stored answer" },
  "created_at": "…",
  "updated_at": "…"
}
```

`status` moves through `pending`, `created`, `refused`, `unknown`, `succeeded`, `failed` and `reversed`. An unknown reference answers `404` `not_found`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.