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

# BillStack API Errors: Status Codes and Handling

> Understand how the BillStack API reports errors - the response shape, the HTTP status codes it uses, and how to handle each one gracefully.

The BillStack API gives you programmatic access to virtual accounts, transactions, and webhooks so you can collect payments and receive real-time notifications from your own systems. Every interaction follows a consistent set of conventions : once you understand them here, they apply uniformly across every endpoint in this reference.

## Base URL

All API requests are made over HTTPS to the following base URL:

```text theme={null}
https://api.billstack.co/v2
```

There is no trailing slash. Every endpoint path in this reference is appended directly to this base URL (e.g., `https://api.billstack.co/v2/reserved-accounts`).

## Request & Response Format

All request bodies must be JSON, and all responses are returned as JSON. Set the `Content-Type` header on every request that includes a body:

```http theme={null}
Content-Type: application/json
```

You do not need to set an `Accept` header : the API always responds with `application/json`.

## Authentication

Authenticate your requests by passing your **secret key** as a Bearer token in the `Authorization` header:

```http theme={null}
Authorization: Bearer Bill_Stack-SEC-KEY-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

Requests made without a valid, active key receive a `401 Unauthorized` response. See the [Authentication](/api-reference/authentication) page for full details on public vs. secret keys and how to rotate them.

## Response Envelope

Every API response : success or error : is wrapped in the same envelope. It always contains a boolean `status`, a human-readable `message`, and a `data` field. List responses additionally include a `meta` object with pagination details:

```json theme={null}
{
  "status": true,
  "message": "OK",
  "data": { ... },
  "meta": {
    "total": 50,
    "page": 1,
    "pageSize": 20,
    "totalPages": 3
  }
}
```

On failure, `status` is `false`, `message` describes what went wrong, and `data` is `null`:

```json theme={null}
{
  "status": false,
  "message": "Invalid or inactive secret key",
  "data": null
}
```

Check the boolean `status` field to determine success or failure, and read `message` for context. See the [Errors](/api-reference/errors) reference for HTTP status codes and how to handle them.

## Pagination

All list endpoints support page-based pagination via two query parameters:

<ParamField query="page" default="1" type="integer">
  The page number to retrieve. Starts at `1`.
</ParamField>

<ParamField query="pageSize" default="20" type="integer">
  The number of results to return per page.
</ParamField>

The response `meta` object tells you where you are in the full result set:

<ResponseField name="meta" type="object">
  Pagination metadata included on all list responses.

  <Expandable title="meta fields">
    <ResponseField name="meta.total" type="integer">
      Total number of records matching the query across all pages.
    </ResponseField>

    <ResponseField name="meta.page" type="integer">
      The current page number.
    </ResponseField>

    <ResponseField name="meta.pageSize" type="integer">
      The number of records returned per page.
    </ResponseField>

    <ResponseField name="meta.totalPages" type="integer">
      The total number of pages available for this query.
    </ResponseField>
  </Expandable>
</ResponseField>

To page through a full result set, request `page=1`, then keep incrementing `page` until it reaches `meta.totalPages`.

## Idempotency

When you initiate a transfer, you can include an `idempotency_key` in the request body to safely retry without risking a duplicate payout. If a transfer with the same key has already been accepted for your account, BillStack returns the existing transfer instead of creating a second one.

```json theme={null}
{
  "idempotency_key": "a8098c1a-f86e-11da-bd1a-00112444be1e",
  "amount": 5000,
  "...": "..."
}
```

Use a UUID or another sufficiently random string as your key, and generate a fresh one per distinct transfer.

<Warning>
  Always include an `idempotency_key` when initiating a transfer. Without it, a network timeout that prompts a retry could send the same payout twice.
</Warning>

***

## Explore the API

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    Learn how to obtain, use, and rotate your public and secret keys.
  </Card>

  <Card title="Errors" icon="circle-exclamation" href="/api-reference/errors">
    Browse the HTTP status codes BillStack returns and how to handle them gracefully.
  </Card>

  <Card title="Create Virtual Account" icon="building-columns" href="/api-reference/virtual-accounts/create">
    Provision a virtual bank account to start collecting payments for a customer.
  </Card>

  <Card title="Webhooks" icon="bolt" href="/webhooks/overview">
    Receive and verify real-time payment and transaction events on your server.
  </Card>
</CardGroup>
