> ## 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.

# Bank Transfer

> Send funds to any Nigerian bank account via NIP (NIBSS Instant Payments).

<Note>
  Transfers may return a `pending` status if the payment network does not respond within the timeout window. The transaction is retried automatically and a webhook is dispatched when the final status is known.
</Note>

## List supported banks

`GET /transfer/banks`

Returns all banks currently supported for outward transfers, sorted alphabetically by name.

### Request

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

### Response

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

<ResponseField name="banks" type="array">
  Array of bank objects.

  <Expandable title="Bank object">
    <ResponseField name="code" type="string">
      Bank sort code. Use this value as `sortCode` in transfer requests.
    </ResponseField>

    <ResponseField name="name" type="string">
      Human-readable bank name.
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.tagpay.ng/v1/transfer/banks" \
    -H "Authorization: Bearer <token>"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.tagpay.ng/v1/transfer/banks", {
    headers: { Authorization: "Bearer <token>" },
  });
  const { banks } = await response.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": true,
  "banks": [
    { "code": "000014", "name": "ACCESS BANK" },
    { "code": "000005", "name": "ACCESS BANK (DIAMOND)" },
    { "code": "000010", "name": "ECOBANK" },
    { "code": "000016", "name": "FIRST BANK OF NIGERIA" },
    { "code": "000013", "name": "GUARANTY TRUST BANK" },
    { "code": "101", "name": "PROVIDUS BANK" },
    { "code": "000022", "name": "STERLING BANK" },
    { "code": "000018", "name": "UNION BANK" },
    { "code": "000004", "name": "UNITED BANK FOR AFRICA" },
    { "code": "000017", "name": "WEMA BANK" },
    { "code": "000015", "name": "ZENITH BANK" }
  ]
}
```

***

## Resolve account details

`GET /transfer/account/details`

Performs a name enquiry (account lookup) to verify a beneficiary account before sending a transfer. You must call this endpoint and confirm the returned `accountName` before initiating a bank transfer via NIP — the NIP route requires the session ID from this lookup.

<Tip>
  Always display the resolved `accountName` to the user and request confirmation before submitting the transfer. Transfers sent to an incorrect account cannot be recalled automatically.
</Tip>

### Request

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

<ParamField query="accountNumber" type="string" required>
  The beneficiary's bank account number.
</ParamField>

<ParamField query="sortCode" type="string" required>
  The beneficiary's bank sort code. Obtain valid sort codes from `GET /transfer/banks`.
</ParamField>

### Response

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

<ResponseField name="account" type="object">
  <Expandable title="account properties">
    <ResponseField name="accountName" type="string">
      The registered name on the beneficiary account.
    </ResponseField>

    <ResponseField name="accountNumber" type="string">
      The account number as returned by the bank.
    </ResponseField>

    <ResponseField name="bankCode" type="string">
      The sort code you provided.
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.tagpay.ng/v1/transfer/account/details?accountNumber=0123456789&sortCode=000013" \
    -H "Authorization: Bearer <token>"
  ```

  ```javascript Node.js theme={null}
  const params = new URLSearchParams({
    accountNumber: "0123456789",
    sortCode: "000013",
  });

  const response = await fetch(
    `https://api.tagpay.ng/v1/transfer/account/details?${params}`,
    { headers: { Authorization: "Bearer <token>" } }
  );
  const data = await response.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": true,
  "account": {
    "accountName": "OKONKWO AMAKA",
    "accountNumber": "0123456789",
    "bankCode": "000013"
  }
}
```

***

## Send a bank transfer

`POST /transfer/bank`

Sends funds from your merchant settlement wallet to any Nigerian bank account. Charges, VAT, and optional stamp duty are deducted from your wallet on top of the transfer amount.

The transfer goes through immediately when called via API key. Requests made through the web dashboard enter a maker-checker approval queue and do not transfer funds until approved.

### Request

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

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

<ParamField body="sortCode" type="string" required>
  Destination bank sort code. Obtain valid codes from `GET /transfer/banks`.
</ParamField>

<ParamField body="accountNumber" type="string" required>
  Destination account number.
</ParamField>

<ParamField body="accountName" type="string" required>
  Beneficiary name as resolved by `GET /transfer/account/details`. Required for NIP transfers.
</ParamField>

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

<ParamField body="metadata" type="object">
  Arbitrary key-value data attached to the transaction. Returned in webhook payloads.
</ParamField>

### Response

<ResponseField name="status" type="boolean">
  `true` when the request was accepted. Note: `status: true` with `transfer.status: "pending"` means the transfer is being retried in the background.
</ResponseField>

<ResponseField name="message" type="string">
  Status message.
</ResponseField>

<ResponseField name="transfer" type="object">
  Transfer result object.

  <Expandable title="transfer properties">
    <ResponseField name="amount" type="number">
      Transfer amount in kobo.
    </ResponseField>

    <ResponseField name="reference" type="string">
      Internal transaction reference.
    </ResponseField>

    <ResponseField name="transactionReference" type="string">
      Reference returned by the payment network (NIP or Providus).
    </ResponseField>

    <ResponseField name="charges" type="number">
      Transfer fee in kobo.
    </ResponseField>

    <ResponseField name="vat" type="number">
      VAT on the transfer fee, in kobo.
    </ResponseField>

    <ResponseField name="total" type="number">
      Total amount deducted from your merchant wallet (amount + charges + VAT).
    </ResponseField>

    <ResponseField name="status" type="string">
      `"success"`, `"pending"`, or `"failed"`.
    </ResponseField>

    <ResponseField name="sessionId" type="string">
      NIP session ID for this transaction.
    </ResponseField>

    <ResponseField name="destination" type="string">
      Encoded destination in the format `accountNumber/sortCode`.
    </ResponseField>

    <ResponseField name="description" type="string">
      Human-readable description of the transfer.
    </ResponseField>

    <ResponseField name="stampDuty" type="number">
      Stamp duty amount charged (if applicable, for NIP transfers above the threshold).
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/transfer/bank \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 5000000,
      "sortCode": "000013",
      "accountNumber": "0123456789",
      "accountName": "OKONKWO AMAKA",
      "narration": "Salary payment May 2024"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.tagpay.ng/v1/transfer/bank", {
    method: "POST",
    headers: {
      "Authorization": "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: 5000000,
      sortCode: "000013",
      accountNumber: "0123456789",
      accountName: "OKONKWO AMAKA",
      narration: "Salary payment May 2024",
    }),
  });

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

```json Response (success) theme={null}
{
  "status": true,
  "message": "Transaction successfully completed.",
  "transfer": {
    "amount": 5000000,
    "reference": "TXN-20240501-ABC123DEF456",
    "transactionReference": "NIP-20240501-XYZ789",
    "charges": 5000,
    "vat": 375,
    "total": 5005375,
    "status": "success",
    "sessionId": "SES-20240501-001",
    "destination": "0123456789/000013",
    "description": "Transfer of NGN50,000.00 to OKONKWO AMAKA (0123456789/Guaranty Trust Bank)"
  }
}
```

```json Response (pending) theme={null}
{
  "status": true,
  "message": "Transaction is processing in the background.",
  "transfer": {
    "amount": 5000000,
    "reference": "TXN-20240501-ABC123DEF456",
    "transactionReference": "TXN-20240501-ABC123DEF456",
    "charges": 5000,
    "vat": 375,
    "total": 5005375,
    "status": "pending",
    "sessionId": "SES-20240501-001",
    "destination": "0123456789/000013",
    "description": "Transfer of NGN50,000.00 to OKONKWO AMAKA (0123456789/Guaranty Trust Bank)"
  }
}
```

***

## Customer-initiated bank transfer

`POST /transfer/bank/customer`

Sends a bank transfer where the funds are debited from a specific customer's wallet rather than from your merchant settlement wallet. The customer's tier limits, daily limits, and minimum balance rules apply.

### Request

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

<ParamField body="customerId" type="string" required>
  UUID of the customer whose wallet will be debited.
</ParamField>

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

<ParamField body="sortCode" type="string" required>
  Destination bank sort code.
</ParamField>

<ParamField body="accountNumber" type="string" required>
  Destination account number.
</ParamField>

<ParamField body="accountName" type="string" required>
  Beneficiary name as returned by account lookup.
</ParamField>

<ParamField body="narration" type="string">
  Transfer narration.
</ParamField>

<ParamField body="reference" type="string">
  Your unique reference for this transaction. If omitted, one is auto-generated.
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary metadata attached to the transaction.
</ParamField>

### Response

Same structure as `POST /transfer/bank`. The `transfer` object is returned with the same fields.

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/transfer/bank/customer \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "customerId": "cust_9f8e7d6c-b5a4-3210-fedc-ba0987654321",
      "amount": 2000000,
      "sortCode": "000016",
      "accountNumber": "3012345678",
      "accountName": "CHIDI EZE",
      "narration": "Rent payment",
      "reference": "REF-CUST-TXN-20240501-001"
    }'
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": true,
  "message": "Transaction successfully completed.",
  "transfer": {
    "amount": 2000000,
    "reference": "REF-CUST-TXN-20240501-001",
    "transactionReference": "NIP-20240501-CUST-001",
    "charges": 5000,
    "vat": 375,
    "total": 2005375,
    "customerId": "cust_9f8e7d6c-b5a4-3210-fedc-ba0987654321",
    "status": "success",
    "sessionID": "SES-CUST-20240501-001",
    "destination": "3012345678/000016",
    "description": "Transfer of NGN20,000.00 to CHIDI EZE (3012345678/First Bank of Nigeria)"
  }
}
```

***

## Error responses

| HTTP Status | Description                                                                                    |
| ----------- | ---------------------------------------------------------------------------------------------- |
| `400`       | Insufficient available balance                                                                 |
| `400`       | Beneficiary account details could not be resolved — call `GET /transfer/account/details` first |
| `400`       | Invalid or unsupported sort code                                                               |
| `400`       | Daily transaction limit exceeded                                                               |
| `400`       | Merchant wallet is inactive                                                                    |
| `400`       | Transaction failed — funds reversed to source wallet                                           |
| `401`       | Missing or invalid authentication token                                                        |
| `403`       | NIP transfers not enabled on this account                                                      |

```json 400 Failed (funds reversed) theme={null}
{
  "status": false,
  "message": "Transaction failed. Kindly verify the transaction details before trying again.",
  "transfer": {
    "amount": 5000000,
    "status": "failed",
    ...
  }
}
```

```json 400 Account Lookup Required theme={null}
{
  "status": false,
  "message": "Please verify beneficiary account details."
}
```
