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

# Create Wallet

> Create and list customer wallets for your merchant account.

## Create a wallet

<Note>
  You must have either a BVN or NIN — or both — to create a wallet. Wallets created without verified identity documents are frozen until verification is completed.
</Note>

`POST /wallet`

Creates a new customer wallet and assigns a dedicated virtual account number. The merchant's settlement wallet is debited a reservation charge upon creation.

If BVN or NIN verification succeeds, the wallet is activated immediately with `status: "ACTIVE"`. If verification fails, the wallet is created but frozen with `status: "FROZEN"`.

### Request

<ParamField header="Authorization" type="string" required>
  Bearer token for your merchant account. Format: `Bearer <token>`
</ParamField>

<ParamField body="firstName" type="string" required>
  Customer's first name. Must match the name on file with the BVN/NIN provider for verification to succeed.
</ParamField>

<ParamField body="lastName" type="string" required>
  Customer's last name.
</ParamField>

<ParamField body="phoneNumber" type="string" required>
  Customer's phone number. Must be unique across your merchant account (unless phone uniqueness checking is disabled). Accepts formats like `08012345678` or `+2348012345678`.
</ParamField>

<ParamField body="dateOfBirth" type="string" required>
  Customer's date of birth in `YYYY-MM-DD` format.
</ParamField>

<ParamField body="bvn" type="string">
  Customer's Bank Verification Number (BVN). Exactly 11 digits, numbers only. Either `bvn` or `nin` is required.
</ParamField>

<ParamField body="nin" type="string">
  Customer's National Identification Number (NIN). Exactly 11 digits, numbers only. Either `bvn` or `nin` is required.
</ParamField>

<ParamField body="email" type="string">
  Customer's email address. If omitted, a placeholder email derived from the phone number is generated automatically.
</ParamField>

<ParamField body="address" type="string">
  Customer's physical address.
</ParamField>

<ParamField body="currency" type="string" default="NGN">
  Wallet currency. Currently only `NGN` is supported.
</ParamField>

<ParamField body="tier" type="string" default="TIER_1">
  Requested wallet tier. One of `TIER_1`, `TIER_2`, or `TIER_3`. The actual assigned tier depends on successful verification — wallets requiring dual BVN and NIN verification may be downgraded to `TIER_1` if either check fails.
</ParamField>

<ParamField body="customerId" type="string">
  If provided, the wallet reservation charge is debited from this existing customer's wallet rather than from your merchant settlement wallet.
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary key-value data you want to attach to the wallet. Returned in webhook payloads.
</ParamField>

<ParamField body="password" type="string">
  Optional password for the customer account. Minimum 6 characters.
</ParamField>

### Response

<ResponseField name="status" type="boolean">
  `true` when the request succeeded.
</ResponseField>

<ResponseField name="wallet" type="object">
  The newly created wallet object.

  <Expandable title="wallet properties">
    <ResponseField name="id" type="string">
      Unique wallet ID (UUID).
    </ResponseField>

    <ResponseField name="accountNumber" type="string">
      10-digit virtual account number assigned to this wallet.
    </ResponseField>

    <ResponseField name="accountName" type="string">
      Account name displayed on transfers — typically the customer's full name.
    </ResponseField>

    <ResponseField name="bankName" type="string">
      Name of the partner bank that issued the virtual account.
    </ResponseField>

    <ResponseField name="bankCode" type="string">
      Sort code of the issuing bank.
    </ResponseField>

    <ResponseField name="currency" type="string">
      Wallet currency (`NGN`).
    </ResponseField>

    <ResponseField name="status" type="string">
      Wallet status: `ACTIVE` or `FROZEN`.
    </ResponseField>

    <ResponseField name="accountReference" type="string">
      Internal account reference assigned by the issuing bank.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="customer" type="object">
  The customer record created alongside the wallet.

  <Expandable title="customer properties">
    <ResponseField name="id" type="string">
      Unique customer ID (UUID). Use this as `customerId` in future wallet and transfer operations.
    </ResponseField>

    <ResponseField name="firstName" type="string">
      Customer's first name.
    </ResponseField>

    <ResponseField name="lastName" type="string">
      Customer's last name.
    </ResponseField>

    <ResponseField name="phoneNumber" type="string">
      Normalized phone number in E.164 format.
    </ResponseField>

    <ResponseField name="email" type="string">
      Customer email address.
    </ResponseField>

    <ResponseField name="tier" type="string">
      Assigned wallet tier (`TIER_1`, `TIER_2`, or `TIER_3`).
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tagpay.ng/v1/wallet \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "firstName": "Amaka",
      "lastName": "Okonkwo",
      "phoneNumber": "08031234567",
      "dateOfBirth": "1990-05-14",
      "bvn": "12345678901",
      "email": "amaka.okonkwo@example.com",
      "tier": "TIER_1"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.tagpay.ng/v1/wallet", {
    method: "POST",
    headers: {
      "Authorization": "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      firstName: "Amaka",
      lastName: "Okonkwo",
      phoneNumber: "08031234567",
      dateOfBirth: "1990-05-14",
      bvn: "12345678901",
      email: "amaka.okonkwo@example.com",
      tier: "TIER_1",
    }),
  });

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

```json Response (201 Created) theme={null}
{
  "status": true,
  "wallet": {
    "id": "wlt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "accountNumber": "0123456789",
    "accountName": "Amaka Okonkwo",
    "bankName": "Providus Bank",
    "bankCode": "101",
    "currency": "NGN",
    "status": "ACTIVE",
    "accountReference": "REF-20240501-001"
  },
  "customer": {
    "id": "cust_9f8e7d6c-b5a4-3210-fedc-ba0987654321",
    "firstName": "Amaka",
    "lastName": "Okonkwo",
    "phoneNumber": "+2348031234567",
    "email": "amaka.okonkwo@example.com",
    "tier": "TIER_1"
  }
}
```

***

## List wallets

`GET /wallet`

Returns a paginated list of all customer wallets for your merchant account, ordered by creation date (newest first).

### Request

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

<ParamField query="page" type="number" default="1">
  Page number for pagination. Must be a positive integer.
</ParamField>

<ParamField query="perPage" type="number" default="20">
  Number of records per page. Must be a positive integer.
</ParamField>

<ParamField query="search" type="string">
  Filter by account name (partial match, case-insensitive).
</ParamField>

<ParamField query="accountNumber" type="string">
  Filter by an exact 10-digit account number. When provided, returns matching wallets directly without standard pagination.
</ParamField>

<ParamField query="phoneNumber" type="string">
  Filter by customer phone number (partial match).
</ParamField>

### Response

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

<ResponseField name="wallets" type="array">
  Array of wallet objects.
</ResponseField>

<ResponseField name="metadata" type="object">
  Pagination metadata.

  <Expandable title="metadata properties">
    <ResponseField name="page" type="number">
      Current page number.
    </ResponseField>

    <ResponseField name="totalRecords" type="number">
      Total number of customer records matching the query.
    </ResponseField>

    <ResponseField name="totalPages" type="number">
      Total number of pages.
    </ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.tagpay.ng/v1/wallet?page=1&perPage=20" \
    -H "Authorization: Bearer <token>"
  ```

  ```bash curl (with filters) theme={null}
  curl "https://api.tagpay.ng/v1/wallet?page=1&perPage=50&search=Amaka" \
    -H "Authorization: Bearer <token>"
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": true,
  "wallets": [
    {
      "id": "wlt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "accountNumber": "0123456789",
      "accountName": "Amaka Okonkwo",
      "availableBalance": 15000,
      "status": "ACTIVE",
      "currency": "NGN",
      "customerId": "cust_9f8e7d6c-b5a4-3210-fedc-ba0987654321",
      "tier": "TIER_1"
    }
  ],
  "metadata": {
    "page": 1,
    "totalRecords": 1,
    "totalPages": 1
  }
}
```

***

## Error responses

| HTTP Status | Description                                                    |
| ----------- | -------------------------------------------------------------- |
| `400`       | Validation error — missing required fields or invalid format   |
| `400`       | BVN or NIN not provided                                        |
| `400`       | Phone number, BVN, or NIN already registered for this merchant |
| `400`       | Insufficient balance for wallet reservation charge             |
| `401`       | Missing or invalid authentication token                        |
| `403`       | API key lacks `CREATE_CUSTOMER_WALLET` permission              |

```json 400 Bad Request theme={null}
{
  "status": false,
  "message": "Please provided either NIN or BVN"
}
```
