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

# Charging flow

> Find charge points, follow your drivers' sessions with webhooks, and read the final energy and cost.

This guide follows one session from the moment a driver plugs in to the final bill. Drivers start and stop their sessions in the ChargeExpress app or at the charger; every session paid from your **fleet wallet** is visible through the API and its webhooks.

You need a key with `fleet:read` (read charge points and sessions), and a webhook endpoint subscribed to the `session.*` events.

> [!TIP]
>
> Build this flow with a sandbox key (`cxk_test_…`) first. In the [sandbox](/guides/sandbox), you run sessions on four simulated chargers from **Developers → Sandbox** in the fleet portal. They run on a simulated meter at 60× real time, finish within about two minutes, and every response and webhook below has the same shape.

```mermaid theme={null}
sequenceDiagram
  participant Driver
  participant CP as Charge point
  participant CX as ChargeExpress API
  participant You as Your system
  Driver->>CP: Starts a charge (app or charger)
  CP->>CX: StartTransaction
  CX-->>You: webhook session.started
  You->>CX: GET /sessions/{id}
  Driver->>CP: Stops the charge or unplugs
  CP->>CX: StopTransaction
  CX-->>You: webhook session.completed
```

## 1. Find charge points

`GET /charge_points` lists the public ChargeExpress network, for example to show your drivers where they can charge, with whether each charger is connected right now and the status of each connector.

```bash theme={null}
curl "https://stage.partners.chargeexpressltd.com/api/public/v1/charge_points?limit=50" \
  -H "Authorization: Bearer $CHARGEEXPRESS_API_KEY"
```

```json Response theme={null}
{
  "data": [
    {
      "object": "charge_point",
      "id": "CX-ACC-0007",
      "description": "Airport City, bay 3",
      "online": true,
      "status": "Operative",
      "max_power_kw": "60",
      "latitude": "5.6052",
      "longitude": "-0.1718",
      "address": {
        "street": "Liberation Road",
        "city": "Accra",
        "country": "Ghana"
      },
      "connectors": [
        { "connector_id": 1, "status": "Available", "rated_power_kw": "60" },
        { "connector_id": 2, "status": "Charging", "rated_power_kw": "60" }
      ]
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

In the sandbox, the list holds only the simulated chargers, each with `simulated: true`.

A charger is usable when it has `online: true` and `status: "Operative"`, and a connector whose `status` is `Available` (or `Preparing`, once a cable is plugged in). Connector statuses are the charger's OCPP 1.6 statuses.

## 2. Follow sessions with webhooks

| Event | When | `data.object.status` |
| - | - | - |
| `session.started` | The charger reported that the transaction started. | `charging` |
| `session.start_failed` | The session never charged: the charger rejected the start, or the driver never plugged in and the start was abandoned. The wallet reservation is released and nothing is billed. | `cancelled` |
| `session.stopped_by_limit` | The session reached its energy budget (a fleet or driver limit, or the wallet's available credit), so ChargeExpress asked the charger to stop. Includes `stop_reason: "budget_reached"`. `session.completed` follows. | `charging` |
| `session.completed` | The session is settled and its final energy and cost are known. | `completed` |

Webhooks can arrive out of order or more than once. Dedupe on the event `id`, and if you only want the latest state, compare `data.object` with what you have or fetch `GET /sessions/{sessionId}`. See [Webhooks](/webhooks/overview).

Session events fire for every session paid from the fleet wallet, whether the driver started it in the app or at the charger.

## 3. Read a session while it runs

`GET /sessions/{sessionId}` returns the session as it is now. While it is charging, `energy_kwh` and `cost` grow with each meter reading and `ended_at` is `null`:

```bash theme={null}
curl https://stage.partners.chargeexpressltd.com/api/public/v1/sessions/48213 \
  -H "Authorization: Bearer $CHARGEEXPRESS_API_KEY"
```

```json Response theme={null}
{
  "object": "session",
  "id": "48213",
  "status": "charging",
  "charge_point_id": "CX-ACC-0007",
  "driver_id": "d3x7n2q9k4m8p1r6t0v5w2yz",
  "vehicle_id": "v6b1c8n3m5k2j9h4g7f0d2sa",
  "energy_kwh": "17.9800",
  "budget_kwh": "40.0000",
  "unit_price": "3.85",
  "cost": "69.23",
  "on_credit": "0.00",
  "currency": "GHS",
  "paid_after_session": false,
  "started_at": "2026-10-13T09:02:11.000Z",
  "stop_requested_at": null,
  "ended_at": null
}
```

Sessions end when the driver stops them in the app or unplugs, or when they reach their budget. `budget_kwh` is the most the session can use: the smallest of any fleet or driver [limit](/api-reference/introduction#limits) and what the wallet can cover.

## 4. Read the result

`session.completed` carries the settled session:

```json session.completed data.object theme={null}
{
  "object": "session",
  "id": "48213",
  "status": "completed",
  "charge_point_id": "CX-ACC-0007",
  "driver_id": "d3x7n2q9k4m8p1r6t0v5w2yz",
  "vehicle_id": "v6b1c8n3m5k2j9h4g7f0d2sa",
  "energy_kwh": "18.4250",
  "budget_kwh": "40.0000",
  "unit_price": "3.85",
  "cost": "70.94",
  "on_credit": "0.00",
  "currency": "GHS",
  "paid_after_session": false,
  "started_at": "2026-10-13T09:02:11.000Z",
  "stop_requested_at": "2026-10-13T09:41:55.000Z",
  "ended_at": "2026-10-13T09:42:30.000Z"
}
```

| Field | Meaning |
| - | - |
| `energy_kwh` | Energy delivered. |
| `cost` | `energy_kwh × unit_price`, rounded up to the pesewa. |
| `on_credit` | The part of the cost that went on your fleet's credit line because prepaid kWh ran out. |
| `paid_after_session` | `true` if the session was paid from the wallet after it finished rather than reserved up front. |

Prepaid energy comes out of the wallet's `balance_kwh`. If `on_credit` is above zero, a **usage invoice** is raised for that part. Its id is the session id (`GET /invoices/usage/48213`), and `invoice.created` fires when the invoice number is assigned. Pay it as described in [Funding flow](/guides/funding-flow#pay-usage-invoices).

To list your fleet's sessions, for example to reconcile a month, use `GET /sessions` with `status`, `driver_id`, `vehicle_id`, `charge_point_id`, `from` and `to` filters.


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