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

# Customers

> Create and manage customers, and give each one a dedicated virtual bank account so you can receive bank-transfer payments attributed to them.

## Overview

A **customer** is a person (or business) you transact with — your end user, buyer,
or payer. You create customers under your account so that payments, invoices, and
other activity can be attributed to a specific person rather than landing in an
anonymous pool.

Each customer record holds basic identity details (name, email, phone) and,
optionally, a **virtual account**: a dedicated Nigerian bank account number tied to
that customer. When money is sent to a customer's virtual account over the bank
network, Hyparrow automatically attributes the incoming transfer to that customer
and records it as a transaction — no manual reconciliation required.

<Note>
  All amounts in the Hyparrow API are expressed in **kobo**, the minor unit of the
  Nigerian Naira. 1 NGN = 100 kobo, so `₦500.00` is `50000`.
</Note>

### Base URL & authentication

All requests go to the production base URL and must be signed with your API key
pair, sent as request headers.

| Item          | Value                               |
| ------------- | ----------------------------------- |
| Base URL      | `https://api.hyparrow.cloud/api/v1` |
| Auth header 1 | `X-API-Key: pk_live_xxx`            |
| Auth header 2 | `X-API-Secret: sk_live_xxx`         |

<Note>
  Build and test against the sandbox first. Point requests at
  `https://sandbox.hyparrow.cloud/api/v1` and use a **`pk_test_`** key (with its
  matching `sk_test_` secret). Sandbox virtual accounts simulate the bank network,
  so you can trigger test transfers without moving real money.
</Note>

## Typical flow

The most common pattern is: create a customer, give them a virtual account, then
receive a bank transfer that Hyparrow attributes back to that customer.

<Steps>
  <Step title="Create the customer">
    Register the person you want to transact with. You get back a customer record
    with a unique `id` (UUID) and a human-friendly `customerCode` (e.g. `HYP_...`).
  </Step>

  <Step title="Create a virtual account for them">
    Call the virtual-account endpoint with the customer's `id` and a `bankCode`.
    Hyparrow provisions a dedicated account number on the bank network and stores
    it on the customer record.
  </Step>

  <Step title="Share the account details">
    Show the returned `accountNumber`, `accountName`, and `bankName` to your
    customer so they can pay by bank transfer.
  </Step>

  <Step title="Receive the payment">
    When the customer sends money to their virtual account, Hyparrow records a
    `virtual_account` transaction attributed to that customer. List or fetch it via
    the [Transactions](/transactions) endpoints, or react to it through webhooks.
  </Step>
</Steps>

## Create a customer

`POST /customers`

Creates a new customer under the authenticated account.

### Request fields

| Field         | Type   | Required | Description                                                                            |
| ------------- | ------ | -------- | -------------------------------------------------------------------------------------- |
| `firstName`   | string | Yes      | Customer's first name.                                                                 |
| `lastName`    | string | Yes      | Customer's last name.                                                                  |
| `email`       | string | Yes      | A valid email address.                                                                 |
| `phoneNumber` | string | Yes      | Customer's phone number.                                                               |
| `dateOfBirth` | string | No       | Date of birth, `YYYY-MM-DD`.                                                           |
| `address`     | string | No       | Street/postal address. Used to resolve the customer's Nigerian state for demographics. |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.hyparrow.cloud/api/v1/customers \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "firstName": "Ada",
      "lastName": "Obi",
      "email": "ada.obi@example.com",
      "phoneNumber": "+2348012345678",
      "dateOfBirth": "1992-04-15",
      "address": "12 Marina Road, Lagos Island, Lagos"
    }'
  ```

  ```json Request body theme={null}
  {
    "firstName": "Ada",
    "lastName": "Obi",
    "email": "ada.obi@example.com",
    "phoneNumber": "+2348012345678",
    "dateOfBirth": "1992-04-15",
    "address": "12 Marina Road, Lagos Island, Lagos"
  }
  ```
</CodeGroup>

### Response

`201 Created`

```json theme={null}
{
  "success": true,
  "message": "Customer created successfully",
  "data": {
    "id": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
    "customerCode": "HYP_8sKd92Lm0Pq4",
    "clientId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "firstName": "Ada",
    "lastName": "Obi",
    "email": "ada.obi@example.com",
    "phoneNumber": "+2348012345678",
    "dateOfBirth": "1992-04-15T00:00:00Z",
    "address": "12 Marina Road, Lagos Island, Lagos",
    "state": "Lagos",
    "status": "active",
    "metadata": {},
    "createdAt": "2026-06-30T09:15:00Z",
    "updatedAt": "2026-06-30T09:15:00Z"
  }
}
```

A newly created customer has `status: "active"` and no virtual account fields yet —
those appear only after you create a virtual account.

## List customers

`GET /customers`

Returns the customers belonging to your account, newest first, with pagination.

### Query parameters

| Parameter | Type    | Default | Description                                     |
| --------- | ------- | ------- | ----------------------------------------------- |
| `page`    | integer | `1`     | Page number.                                    |
| `limit`   | integer | `20`    | Results per page.                               |
| `status`  | string  | —       | Filter by `active`, `suspended`, or `inactive`. |

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.hyparrow.cloud/api/v1/customers?page=1&limit=20&status=active" \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx"
  ```
</CodeGroup>

### Response

`200 OK`

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
      "customerCode": "HYP_8sKd92Lm0Pq4",
      "firstName": "Ada",
      "lastName": "Obi",
      "email": "ada.obi@example.com",
      "phoneNumber": "+2348012345678",
      "state": "Lagos",
      "status": "active",
      "createdAt": "2026-06-30T09:15:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1
  }
}
```

## Get a customer

`GET /customers/{id}`

Retrieves a single customer. The `{id}` path parameter accepts **either** the
customer UUID **or** the `HYP_` customer code.

<CodeGroup>
  ```bash By UUID theme={null}
  curl "https://api.hyparrow.cloud/api/v1/customers/9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21" \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx"
  ```

  ```bash By customer code theme={null}
  curl "https://api.hyparrow.cloud/api/v1/customers/HYP_8sKd92Lm0Pq4" \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx"
  ```
</CodeGroup>

### Response

`200 OK`

```json theme={null}
{
  "success": true,
  "data": {
    "id": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
    "customerCode": "HYP_8sKd92Lm0Pq4",
    "firstName": "Ada",
    "lastName": "Obi",
    "email": "ada.obi@example.com",
    "phoneNumber": "+2348012345678",
    "state": "Lagos",
    "status": "active",
    "accountNumber": "1234567890",
    "accountName": "HYPARROW/Ada Obi",
    "bankCode": "035",
    "bankName": "Example Microfinance Bank",
    "createdAt": "2026-06-30T09:15:00Z",
    "updatedAt": "2026-06-30T09:20:00Z"
  }
}
```

## Create a customer virtual account

`POST /customers/virtual-account`

Provisions a **dedicated virtual bank account** for an existing customer. A virtual
account is a real, transfer-receiving account number on the bank network that is
permanently tied to one customer. Anyone who sends a bank transfer to it — from any
Nigerian bank app — pays that customer, and Hyparrow records the incoming money as a
`virtual_account` transaction attributed to them.

This removes manual reconciliation: instead of asking payers to add a reference, you
give each customer their own account number and let the destination identify them.

### Request fields

| Field        | Type          | Required | Description                                                       |
| ------------ | ------------- | -------- | ----------------------------------------------------------------- |
| `customerId` | string (UUID) | Yes      | The customer the account belongs to. Must belong to your account. |
| `bankCode`   | string        | Yes      | The bank network code to provision the account under.             |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.hyparrow.cloud/api/v1/customers/virtual-account \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "customerId": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
      "bankCode": "035"
    }'
  ```
</CodeGroup>

### Response

`201 Created`

```json theme={null}
{
  "success": true,
  "message": "Virtual account created successfully",
  "data": {
    "id": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
    "customerCode": "HYP_8sKd92Lm0Pq4",
    "firstName": "Ada",
    "lastName": "Obi",
    "status": "active",
    "accountNumber": "1234567890",
    "accountName": "HYPARROW/Ada Obi",
    "bankCode": "035",
    "bankName": "Example Microfinance Bank",
    "updatedAt": "2026-06-30T09:20:00Z"
  }
}
```

By default the generated `accountName` carries the `HYPARROW` prefix (for example
`HYPARROW/Ada Obi`), which is what payers see in their banking app.

## Create a virtual account with a custom prefix

`POST /customers/virtual-account/custom`

Works exactly like the standard endpoint above, but lets you replace the default
`HYPARROW` prefix on the account name with your own brand. Useful when you want the
payer to see your business name in their transfer screen.

### Request fields

| Field        | Type          | Required | Description                                           |
| ------------ | ------------- | -------- | ----------------------------------------------------- |
| `customerId` | string (UUID) | Yes      | The customer the account belongs to.                  |
| `bankCode`   | string        | Yes      | The bank network code to provision the account under. |
| `prefix`     | string        | Yes      | Your custom account-name prefix (e.g. your brand).    |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.hyparrow.cloud/api/v1/customers/virtual-account/custom \
    -H "X-API-Key: pk_live_xxx" \
    -H "X-API-Secret: sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "customerId": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
      "bankCode": "035",
      "prefix": "ACME"
    }'
  ```
</CodeGroup>

### Response

`201 Created`

```json theme={null}
{
  "success": true,
  "message": "Virtual account created successfully",
  "data": {
    "id": "9f1c2e6a-3b4d-4c8e-9a12-7d6f5b8c0e21",
    "customerCode": "HYP_8sKd92Lm0Pq4",
    "firstName": "Ada",
    "lastName": "Obi",
    "status": "active",
    "accountNumber": "1234567890",
    "accountName": "ACME/Ada Obi",
    "bankCode": "035",
    "bankName": "Example Microfinance Bank",
    "updatedAt": "2026-06-30T09:25:00Z"
  }
}
```

## Errors & edge cases

The API returns a non-2xx status with `success: false` and an `error` message.

| Status             | When                                                | Example `error`                             |
| ------------------ | --------------------------------------------------- | ------------------------------------------- |
| `400 Bad Request`  | Missing/invalid fields, bad UUID, or invalid email. | `"invalid customer ID"`                     |
| `401 Unauthorized` | Missing or invalid `X-API-Key` / `X-API-Secret`.    | `"client not authenticated"`                |
| `403 Forbidden`    | The customer exists but belongs to another account. | `"customer does not belong to this client"` |
| `404 Not Found`    | No customer matches the given id or code.           | `"customer not found"`                      |

```json theme={null}
{
  "success": false,
  "error": "customer does not belong to this client"
}
```

Other things to keep in mind:

* A virtual account is **permanent** for a customer. Once created, share the same
  `accountNumber` for all of that customer's future transfers.
* The `bankCode` must be a code supported by the bank network; an unsupported code
  returns `400`.
* On `GET /customers/{id}`, a UUID-looking value that isn't a real customer returns
  `404`; a value that is neither a UUID nor a `HYP_` code returns `400`.
