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

# Bill payments overview

> The catalog, the enquiry, and the payment — three objects and one strict order.

Bill payments pay a Nigerian biller — electricity, cable TV, airtime, data, betting, school fees — from one of your NGN accounts. Everything here is NGN, and everything here goes through the same three steps.

## The order is not optional

```mermaid theme={null}
flowchart LR
    C["Catalog<br/>groups → billers → packages"] --> E["Enquiry<br/>who is this customer?<br/>10 minutes"]
    E --> P["Payment<br/>spends the enquiry"]
    P --> V["Vend<br/>submitted → pending → confirmed"]
```

You cannot pay a bill without an enquiry, and an enquiry expires after **ten minutes**. That is the shape of the service: identify the product, confirm the customer, then pay.

## Catalog

Three levels, each paged, all read-only.

| Level | What it is | Example |
| - | - | - |
| Group | A kind of bill | Airtime, Data, Electricity, Cable TV |
| Biller | A specific provider | Example Disco, Example Telco |
| Package | A product that biller sells | Prepaid, Postpaid, a data bundle |

```json theme={null}
{
  "id": "01KZXPYGX5VZXDH9VHJ4YTPCB9",
  "groupId": "01KZXPYGX5VZXDH9VHJ4YTPCA8",
  "name": "Example Telco",
  "slug": "example-telco",
  "logo": null,
  "requireVerification": false,
  "status": "active"
}
```

Catalog `id`s are Sakawave ULIDs, and they are the only addresses this API accepts — in a path and in an enquiry body alike. A slug will not resolve, and neither will the upstream provider's own id, which is what `id` returned before. Which provider fulfils a product is internal routing that never appears here, so a provider change leaves your stored ids intact.

<Note>
  The catalog and payment lists use their own page shape — `totalPages` instead of `pageCount`, and no `hasNext` or `hasPrevious`. This is the only part of the API that does.
</Note>

## Enquiry

An enquiry asks the biller who a customer reference belongs to, and what paying them will cost.

```json theme={null}
{
  "id": "01K2Z3AB4W5X6Y7Z8ABCDEFGHJ",
  "billerId": "01KZXPYGX5VZXDH9VHJ4YTPCC1",
  "packageId": "01KZXPYGX5VZXDH9VHJ4YTPCD2",
  "customer": { "customerName": "ADA OKAFOR", "address": "14 Marina Road", "canVend": true, "minimumVend": "500.00" },
  "totalDue": null,
  "minimumAmount": "500.00",
  "charge": "100.00",
  "commission": "0.00",
  "totalDebit": "5100.00",
  "expiresAt": "2026-08-14T09:20:00.000Z"
}
```

Two things it gives you that nothing else can:

1. **The name the biller holds.** Show it before taking money — it is the only check that the meter or account number was typed correctly.
2. **The price.** `charge` and `commission` are yours; `totalDebit` is what leaves the account.

`customer` is whatever the biller returned, filtered to a safe subset, and its shape varies by biller. Read defensively.

## Payment

```json theme={null}
{
  "id": "01K2Z3AB4X5Y6Z7A8BCDEFGHJK",
  "status": "confirmed",
  "amount": "5000.00",
  "charge": "100.00",
  "totalDebit": "5100.00",
  "vendStatus": "SUCCESSFUL",
  "tokenData": { "token": "1234-5678-9012-3456-7890", "units": "31.4" },
  "customerReferenceLast4": "7788"
}
```

| Status | Meaning |
| - | - |
| `submitted` | Sent to the biller. Your account is already debited. |
| `pending` | No final answer yet. A reconciler keeps asking, up to five times. |
| `confirmed` | Value delivered. **The success state — not `completed`.** |
| `failed` | The biller could not deliver. **The debit is reversed automatically.** |

A failed bill payment refunds itself. You do not claim the money back; Sakawave posts a reversal against the same account.

## Amounts are decimals here

This service uses **decimal strings** — `"5000.00"` — not the minor units the rest of the API uses.

| Service | ₦5,000 is written |
| - | - |
| Accounts, transfers, cards | `"500000"` |
| **Bill payments** | `"5000.00"` |

One API, two conventions. Convert at the boundary of this service and nowhere else.

## Events

| Event | When |
| - | - |
| `bills_payment.created` | The payment was submitted |
| `bills_payment.completed` | The biller confirmed it |
| `bills_payment.failed` | It failed, and the debit was reversed |

## Next

<CardGroup cols={2}>
  <Card title="Introduction" icon="book-open" href="/services/bill-payments/introduction">
    Why the enquiry exists, and what it protects.
  </Card>

  <Card title="Get started" icon="play" href="/services/bill-payments/get-started">
    Catalog, enquiry, payment, token.
  </Card>

  <Card title="Setup and configuration" icon="sliders" href="/services/bill-payments/setup-and-configuration">
    Limits, idempotency, and reconciliation.
  </Card>

  <Card title="Airtime, data, and utilities" icon="zap" href="/services/bill-payments/airtime-data-and-utilities">
    How the product families differ.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.