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

# Bill Payment Integration Overview

> Discover and pay Algerian utility and telecom bills

## Introduction

Bill Payment lets you pay Algerian utility and telecom bills on behalf of your own customers. You ask a biller what an account owes, you pay one of the bills that comes back, you follow it to a final state, and you keep the receipt.

The whole product is five calls. This page is the map; each step below links to a guide with working code in cURL, Node.js, Python and PHP.

<Note>
  Bill Payment lives on **`https://billapi.oneclickdz.com`** — a different base URL from the rest of the platform. The authentication header is the same one you already use: `X-Access-Token`.
</Note>

## How it works

```mermaid theme={null}
sequenceDiagram
    participant Customer
    participant YourApp
    participant API as Bill Payment API

    YourApp->>API: 1. GET /v3/partners
    API-->>YourApp: Availability map

    Customer->>YourApp: Enters account number
    YourApp->>API: 2. POST /v3/bills/discover
    API-->>YourApp: transactionId (PENDING)

    loop Until READY
        YourApp->>API: GET /v3/bills/transactions/{id}
        API-->>YourApp: Status
    end

    API-->>YourApp: READY + bills[]
    YourApp->>Customer: Shows amount + fee
    Customer->>YourApp: Confirms

    YourApp->>API: 3. POST /v3/bills/pay
    API-->>YourApp: PROCESSING

    loop 4. Until final
        YourApp->>API: GET /v3/bills/transactions/{id}
        API-->>YourApp: Status
    end

    API-->>YourApp: SUCCESS + operationId
    YourApp->>API: 5. GET .../receipt
    API-->>YourApp: Receipt file
    YourApp->>Customer: Confirmation + receipt
```

## The five steps

<Steps>
  <Step title="Check the biller is available">
    Read the availability map and hide any biller that is `UNAVAILABLE` before your customer starts filling in a form.

    → [Step 1: Partners and accounts](/en/bill-payment-guides/1-partners-and-accounts)
  </Step>

  <Step title="Discover what is owed">
    Send the partner, the account identifier and your own `ref`. You get a `transactionId` back; the bills arrive on that transaction a moment later.

    → [Step 2: Discovering bills](/en/bill-payment-guides/2-discovering-bills)
  </Step>

  <Step title="Pay one bill">
    Pick a `billId` from `bills[]`, show your customer `amount + fee`, and submit the payment with a new `ref`.

    → [Step 3: Paying bills](/en/bill-payment-guides/3-paying-bills)
  </Step>

  <Step title="Poll until the status is final">
    `SUCCESS`, `FAILED` or `REFUNDED`. `UNKNOWN` means keep polling — never refund your customer and never retry the payment while it lasts.

    → [Step 4: Status polling](/en/bill-payment-guides/4-status-polling)
  </Step>

  <Step title="Store the receipt and reconcile">
    Download the receipt, store it with `operationId`, and reconcile daily against your own ledger.

    → [Step 5: Receipts and reconciliation](/en/bill-payment-guides/5-receipts-and-reconciliation)
  </Step>
</Steps>

## What you need to know

### Everything is asynchronous

`POST /v3/bills/discover` and `POST /v3/bills/pay` both answer `200` immediately. That `200` means **accepted**, not **done**.

<Warning>
  A `200` from `pay` does not mean the bill was paid. The real outcome only ever appears in the transaction's `status`. Design your integration around polling from the first line of code — retrofitting it later is how customers get charged twice.
</Warning>

### The billers and their identifiers

Five billers, each with one identifier field. Send the field that belongs to the partner; the API returns the same field back on every transaction.

| Partner           | What it is                 | Identifier       |
| ----------------- | -------------------------- | ---------------- |
| `ADE`             | Water                      | `reference`      |
| `SONELGAZ`        | Electricity and gas        | `contractNumber` |
| `SEAAL`           | Water — Algiers and Tipaza | `reference`      |
| `AADL`            | Housing instalments        | `aadlNumber`     |
| `Algérie Télécom` | Landline and internet      | `phoneNumber`    |

`SEAAL` and `AADL` are currently `UNAVAILABLE` in both sandbox and production. Read the availability map rather than hard-coding this.

→ [Identifier rules, formats and examples](/en/bill-payment-guides/1-partners-and-accounts)

### The seven statuses

| Status       | Meaning                                      | Final   |
| ------------ | -------------------------------------------- | ------- |
| `PENDING`    | Accepted; discovery has not finished         | No      |
| `READY`      | Discovery finished — read `bills[]`          | No      |
| `PROCESSING` | Payment in flight                            | No      |
| `SUCCESS`    | Paid; `operationId` and `receiptUrl` present | Yes     |
| `FAILED`     | Did not go through; no money moved           | Yes     |
| `REFUNDED`   | Money moved and was returned in full         | Yes     |
| `UNKNOWN`    | Outcome not yet confirmed; under review      | Not yet |

→ [The full state machine and a production-grade poller](/en/bill-payment-guides/4-status-polling)

### Fees and the 200 DZD floor

Every bill carries its own money fields:

* `amount` — what the biller is owed, in DZD.

* `fee` — the OneClickDz service fee, a percentage of the amount clamped between a minimum and a maximum, **set per biller**:

  | Biller            | Percentage | Minimum | Maximum |
  | ----------------- | ---------- | ------- | ------- |
  | `ADE`             | 0.5%       | 30 DZD  | 60 DZD  |
  | `SONELGAZ`        | 0.5%       | 30 DZD  | 60 DZD  |
  | `Algérie Télécom` | 0.5%       | 10 DZD  | 50 DZD  |

  In practice most bills pay the minimum: 0.5% only exceeds 30 DZD above a 6,000 DZD bill. These rates are configuration and can be adjusted, so read `fee` from the response rather than recomputing it.

* `total` — `amount + fee`, the figure debited from your balance.

Bills below **200 DZD** are filtered out during discovery and never appear in `bills[]`. A `READY` transaction with an empty `bills[]` therefore means either "nothing is due" or "everything due is below the floor" — the API does not distinguish. Tell your customer "no bills are payable right now", not "you owe nothing".

### Your reference is your safety net

`ref` is required on both `discover` and `pay`, is at most 100 characters, and must be unique among your live transactions for that biller. Reusing one answers `403 DUPLICATED_REF`.

Derive it from something you already store, so that after a timeout you can always ask [what that `ref` became](/en/api-reference/bill-payment/check-by-ref) instead of sending the request again.

<Note>
  Use a **different** `ref` for the discovery and for the payment. The transaction keeps its original discovery `ref`, and that is the one `by-ref` looks up.
</Note>

### Sandbox

Sandbox uses the same host, the same routes, the same envelope and the same lifecycle. The only difference is that a sandbox key never reaches a biller and never moves money. The outcome you get is chosen by the account identifier you send, so you can reproduce a decline, a refund and an unconfirmed payment on demand.

Every key is bound to one environment. Call [Validate API Key](/en/api-reference/bill-payment/validate-key) and read `key.type` to prove which one you are holding.

→ [Every sandbox scenario, and a go-live checklist](/en/bill-payment-guides/6-sandbox-testing)

## Key points

<AccordionGroup>
  <Accordion title="200 is an acknowledgement, not an outcome" icon="triangle-exclamation">
    Both write endpoints accept the work and answer immediately. The result lives in the transaction's `status`.

    → [Step 4: Status polling](/en/bill-payment-guides/4-status-polling)
  </Accordion>

  <Accordion title="Never retry a payment on UNKNOWN" icon="ban">
    `UNKNOWN` means the outcome is not confirmed yet. Keep polling — it resolves to `SUCCESS` or `REFUNDED`. Refunding your own customer or resending the payment while it lasts is how money is lost twice.

    → [Handling UNKNOWN](/en/bill-payment-guides/4-status-polling)
  </Accordion>

  <Accordion title="Look up, do not resend" icon="magnifying-glass">
    Every timeout, every `DUPLICATED_REF`, every unexplained failure is answered by looking the `ref` up. A second write is never the right recovery.

    → [Step 2: Discovering bills](/en/bill-payment-guides/2-discovering-bills)
  </Accordion>

  <Accordion title="Read fee and total from the response" icon="calculator">
    Fees are configured per partner and can change. Charge your customer the `total` the API returned, never a figure you calculated.

    → [Step 3: Paying bills](/en/bill-payment-guides/3-paying-bills)
  </Accordion>

  <Accordion title="A foreign transaction is a 404" icon="shield-halved">
    A transaction that is not yours — or that belongs to the other environment — returns `404`, never `403`. The API never confirms that someone else's transaction exists.

    → [Get Transaction by ID](/en/api-reference/bill-payment/check-by-id)
  </Accordion>
</AccordionGroup>

## API Reference

<CardGroup cols={2}>
  <Card title="Validate API Key" icon="key" href="/en/api-reference/bill-payment/validate-key">
    GET /v3/validate
  </Card>

  <Card title="List Partners" icon="building-columns" href="/en/api-reference/bill-payment/list-partners">
    GET /v3/partners
  </Card>

  <Card title="Discover Bills" icon="magnifying-glass-dollar" href="/en/api-reference/bill-payment/discover-bills">
    POST /v3/bills/discover
  </Card>

  <Card title="Pay a Bill" icon="money-bill-transfer" href="/en/api-reference/bill-payment/pay-bill">
    POST /v3/bills/pay
  </Card>

  <Card title="Get Transaction by ID" icon="id-card" href="/en/api-reference/bill-payment/check-by-id">
    GET /v3/bills/transactions/id
  </Card>

  <Card title="Get Transaction by Reference" icon="tag" href="/en/api-reference/bill-payment/check-by-ref">
    GET /v3/bills/transactions/by-ref
  </Card>

  <Card title="List Transactions" icon="list" href="/en/api-reference/bill-payment/list-transactions">
    GET /v3/bills/transactions
  </Card>

  <Card title="Download Receipt" icon="file-arrow-down" href="/en/api-reference/bill-payment/get-receipt">
    GET /v3/bills/transactions/id/receipt
  </Card>
</CardGroup>

## Start integrating

<Card title="Begin with Step 1: Partners and accounts" icon="play" href="/en/bill-payment-guides/1-partners-and-accounts" color="#0D9373">
  Check availability and learn the identifier rules for each biller
</Card>

## Additional resources

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/en/authentication">
    Keys, headers and environments
  </Card>

  <Card title="Response Format" icon="code" href="/en/api-reference/response-format">
    The envelope every endpoint returns
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/en/api-reference/error-handling">
    Every error code and what to do about it
  </Card>

  <Card title="Polling Strategies" icon="chart-line" href="/en/polling-strategies">
    Intervals, backoff and ceilings
  </Card>

  <Card title="Security Best Practices" icon="shield-check" href="/en/security-best-practices">
    Protect your keys and your customers
  </Card>

  <Card title="Contact Support" icon="headset" href="/en/contact">
    Get help from our team
  </Card>
</CardGroup>
