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

# Batch Transfer

> Send funds to multiple bank accounts or wallets in a single request.

## Batch bank transfer

`POST /transfer/bank/batch`

Sends multiple bank transfers in a single request, debiting your merchant settlement wallet for each transaction. Transfers are processed sequentially — each transfer is attempted individually and may succeed, fail (with automatic reversal), or enter a `pending` state for background retry.

The response includes separate `accepted` and `rejected` arrays so you can identify which transfers succeeded and which failed without having to query each transaction individually.

<Warning>
  Ensure you resolve each beneficiary account with `GET /transfer/account/details` before submitting. Transfers to unverified accounts may be rejected by the NIP network. Funds for rejected or reversed transfers are returned to your merchant wallet automatically.
</Warning>

### Request

<ParamField header="Authorization" type="string" required>
  Bearer token. Requires `MANAGE_TRANSFER` permission.
</ParamField>

The request body is a JSON **array** of transfer objects. At least one item is required.

<ParamField body="[].amount" type="number" required>
  Transfer amount in kobo for this item. Must be greater than 0.
</ParamField>

<ParamField body="[].sortCode" type="string" required>
  Bank sort code for the beneficiary. Obtain valid codes from `GET /transfer/banks`.
</ParamField>

<ParamField body="[].accountNumber" type="string" required>
  Beneficiary account number.
</ParamField>

<ParamField body="[].accountName" type="string" required>
  Beneficiary account name as resolved by `GET /transfer/account/details`.
</ParamField>

<ParamField body="[].narration" type="string">
  Transfer narration visible to the beneficiary.
</ParamField>

### Response

<ResponseField name="status" type="boolean">
  `true` on success.
</ResponseField>

<ResponseField name="message" type="string">
  `"Transaction has been successfully completed."`
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="data properties">
    <ResponseField name="reference" type="string">
      Auto-generated batch reference for the entire operation.
    </ResponseField>

    <ResponseField name="all" type="array">
      All transaction records attempted, including amounts, sort codes, and charges.
    </ResponseField>

    <ResponseField name="accepted" type="array">
      Transfers that completed successfully or entered pending retry. Each item includes `reference`, `amount`, `sortCode`, `accountNumber`, `accountName`, and network `metadata`.
    </ResponseField>

    <ResponseField name="rejected" type="array">
      Transfers that failed outright. Each item includes the original transaction fields plus a `reason` string explaining the failure. Funds for rejected transfers are reversed to your merchant wallet.
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/transfer/bank/batch \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '[
      {
        "amount": 5000000,
        "sortCode": "000013",
        "accountNumber": "0123456789",
        "accountName": "OKONKWO AMAKA",
        "narration": "Salary May 2024"
      },
      {
        "amount": 3000000,
        "sortCode": "000016",
        "accountNumber": "3012345678",
        "accountName": "CHIDI EZE",
        "narration": "Bonus payment"
      },
      {
        "amount": 1500000,
        "sortCode": "000004",
        "accountNumber": "2098765432",
        "accountName": "NGOZI ADAEZE",
        "narration": "Freelance payment"
      }
    ]'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.tagpay.ng/v1/transfer/bank/batch", {
    method: "POST",
    headers: {
      "Authorization": "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify([
      {
        amount: 5000000,
        sortCode: "000013",
        accountNumber: "0123456789",
        accountName: "OKONKWO AMAKA",
        narration: "Salary May 2024",
      },
      {
        amount: 3000000,
        sortCode: "000016",
        accountNumber: "3012345678",
        accountName: "CHIDI EZE",
        narration: "Bonus payment",
      },
      {
        amount: 1500000,
        sortCode: "000004",
        accountNumber: "2098765432",
        accountName: "NGOZI ADAEZE",
        narration: "Freelance payment",
      },
    ]),
  });

  const data = await response.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": true,
  "message": "Transaction has been successfully completed.",
  "data": {
    "reference": "BATCH-20240501-TXN-XYZ001",
    "all": [
      {
        "amount": 5000000,
        "sortCode": "000013",
        "accountNumber": "0123456789",
        "accountName": "OKONKWO AMAKA",
        "narration": "Salary May 2024",
        "charges": 5000,
        "vat": 375,
        "total": 5005375,
        "reference": "TXN-20240501-A1B2C3",
        "bankName": "GUARANTY TRUST BANK"
      },
      {
        "amount": 3000000,
        "sortCode": "000016",
        "accountNumber": "3012345678",
        "accountName": "CHIDI EZE",
        "narration": "Bonus payment",
        "charges": 5000,
        "vat": 375,
        "total": 3005375,
        "reference": "TXN-20240501-D4E5F6",
        "bankName": "FIRST BANK OF NIGERIA"
      },
      {
        "amount": 1500000,
        "sortCode": "000004",
        "accountNumber": "2098765432",
        "accountName": "NGOZI ADAEZE",
        "narration": "Freelance payment",
        "charges": 5000,
        "vat": 375,
        "total": 1505375,
        "reference": "TXN-20240501-G7H8I9",
        "bankName": "UNITED BANK FOR AFRICA"
      }
    ],
    "accepted": [
      {
        "amount": 5000000,
        "reference": "TXN-20240501-A1B2C3",
        "accountName": "OKONKWO AMAKA",
        "accountNumber": "0123456789",
        "metadata": {
          "transactionReference": "NIP-20240501-001",
          "responseMessage": "Approved"
        }
      },
      {
        "amount": 3000000,
        "reference": "TXN-20240501-D4E5F6",
        "accountName": "CHIDI EZE",
        "accountNumber": "3012345678",
        "metadata": {
          "transactionReference": "NIP-20240501-002",
          "responseMessage": "Approved"
        }
      }
    ],
    "rejected": [
      {
        "amount": 1500000,
        "reference": "TXN-20240501-G7H8I9",
        "accountName": "NGOZI ADAEZE",
        "accountNumber": "2098765432",
        "reason": "Transaction failed. Unable to resolve recipient details",
        "metadata": {
          "responseMessage": "Beneficiary account not found"
        }
      }
    ]
  }
}
```

***

## CSV bulk customer transfer

`POST /wallet/bulk-csv-customer-transfer`

Sends bank transfers to multiple recipients by uploading a CSV file. Each row in the CSV becomes a separate bank transfer debited from your merchant wallet. Processing is asynchronous.

<Note>
  This endpoint uses multipart form upload. The file field name must be `list`. Processing may take several minutes depending on the size of the file.
</Note>

### Request

<ParamField header="Authorization" type="string" required>
  Bearer token.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `multipart/form-data`
</ParamField>

<ParamField body="list" type="file" required>
  CSV file containing transfer instructions. One transfer per row.
</ParamField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/wallet/bulk-csv-customer-transfer \
    -H "Authorization: Bearer <token>" \
    -F "list=@/path/to/transfers.csv"
  ```
</CodeGroup>

***

## CSV bulk wallet transfer

`POST /wallet/bulk-csv-wallet-transfer`

Similar to CSV bulk customer transfer, but transfers funds between customer wallets rather than to external bank accounts. Each row specifies source and destination wallet account numbers.

### Request

<ParamField header="Authorization" type="string" required>
  Bearer token.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `multipart/form-data`
</ParamField>

<ParamField body="list" type="file" required>
  CSV file containing wallet-to-wallet transfer instructions. The file field name must be `list`.
</ParamField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/wallet/bulk-csv-wallet-transfer \
    -H "Authorization: Bearer <token>" \
    -F "list=@/path/to/wallet-transfers.csv"
  ```
</CodeGroup>

***

## Batch status tracking

After submitting a batch transfer, monitor the status of individual transactions using the `reference` values returned in the `accepted` array. Use your webhook endpoint to receive real-time updates.

**Webhook events fired after batch processing:**

| Event                          | Description                                                                 |
| ------------------------------ | --------------------------------------------------------------------------- |
| `bank_transfer`                | Fired for each individual bank transfer that completes (success or failure) |
| `batch_merchant_bank_transfer` | Fired once for the entire batch when all transfers have been resolved       |

**Transaction statuses:**

| Status    | Description                                                                             |
| --------- | --------------------------------------------------------------------------------------- |
| `success` | Transfer completed and funds credited to beneficiary                                    |
| `pending` | Transfer submitted to the payment network; awaiting confirmation. Automatically retried |
| `failed`  | Transfer failed definitively; funds reversed to your merchant wallet                    |

<Tip>
  Store the `data.reference` (batch reference) and all individual `reference` values from `data.accepted` immediately. You'll need these to reconcile your records if webhook delivery is delayed or you need to query transaction history.
</Tip>

***

## Error responses

| HTTP Status | Description                                                     |
| ----------- | --------------------------------------------------------------- |
| `400`       | Insufficient merchant wallet balance for the total batch amount |
| `400`       | Daily transaction limit exceeded                                |
| `400`       | Merchant wallet is inactive                                     |
| `400`       | Empty batch — at least one transfer item required               |
| `400`       | Lien restriction on account — contact support                   |
| `401`       | Missing or invalid authentication token                         |
| `403`       | NIP transfers not enabled on this account                       |

```json 400 Insufficient Balance theme={null}
{
  "status": false,
  "message": "Insufficient available balance for this transaction."
}
```

```json 400 Daily Limit theme={null}
{
  "status": false,
  "message": "Daily transaction limit exceeded.."
}
```
