> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ocpplab.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ocpplab.io/_mcp/server.

# Quickstart

You need an OCPPLab token and the WebSocket URL of your CSMS.

#### Set it up with your coding agent

Add the OCPPLab SDK to this project and put two virtual chargers online against my CSMS. Follow the [OCPPLab quickstart](https://docs.ocpplab.io/get-started/quickstart) step by step, in this project's language (TypeScript or Python). Read the token from the `OCPPLAB_TOKEN` environment variable and the CSMS URL from `CSMS_WS_URL`; never write either into a file.

#### Install the SDK

**`TypeScript`**

```bash TypeScript
npm i ocpplab
```

**`Python`**

```bash Python
pip install ocpplab
```

#### Set your token and CSMS URL

Generate a token in Studio under **Settings → SDK tokens**. It is shown once.

```bash
export OCPPLAB_TOKEN="<token>"
export CSMS_WS_URL="wss://csms.example.com/ocpp"
```

#### Deploy the chargers

The script creates a location with two chargers, then polls their deployment stage until both are `online`.

```typescript title={"quickstart.ts"}
// Put virtual chargers online against your CSMS, then wait until they connect.
//
//     export OCPPLAB_TOKEN="<api-key>"
//     export CSMS_WS_URL="wss://csms.example.com/ocpp"
//     npx tsx examples/quickstart.ts
//
// Creating a location returns 202 at once; the chargers deploy in the background,
// so this polls their deployment stage until every one is online.
import { OcpplabSDK } from "ocpplab";

const IDENTITIES = ["DEMO-CP-001", "DEMO-CP-002"];

async function main(): Promise<void> {
    // Defaults to https://api.ocpplab.io; pass baseUrl for another host.
    const client = new OcpplabSDK({ token: process.env.OCPPLAB_TOKEN! });
    const accepted = await client.evcharger.location.create({
        name: "Demo hub",
        address: "1 Parvis de la Defense",
        city: "Puteaux",
        country: "FRA",
        coordinates: { lat: 48.892, lng: 2.238 },
        chargers: IDENTITIES.map((identity) => ({
            identity,
            brand_slug: "wallbox",
            model: "wallbox-pulsar-plus",
            connector_type: "Type2",
            ws_url: process.env.CSMS_WS_URL!,
        })),
    });
    console.log(`location ${accepted.location_id}: ${accepted.detail}`);

    const deadline = Date.now() + 600_000;
    while (true) {
        const { items: chargers } = await client.evcharger.deploymentRuntimeOps.status({
            identity: IDENTITIES,
        });
        for (const charger of chargers) {
            console.log(charger.identity, charger.stage, charger.outcome, charger.hint ?? "");
        }
        if (chargers.length > 0 && chargers.every((charger) => charger.stage === "online")) {
            return;
        }
        if (chargers.some((charger) => charger.outcome === "failed" || charger.outcome === "stuck")) {
            throw new Error("a charger failed to deploy; see the hint above");
        }
        if (Date.now() > deadline) {
            throw new Error("chargers were not online after 10 minutes");
        }
        await new Promise((resolve) => setTimeout(resolve, 5_000));
    }
}

void main();

```

```python title={"quickstart.py"}
"""Put virtual chargers online against your CSMS, then wait until they connect.

    export OCPPLAB_TOKEN="<api-key>"
    export CSMS_WS_URL="wss://csms.example.com/ocpp"
    uv run python examples/quickstart.py

Creating a location returns 202 at once; the chargers deploy in the background,
so this polls their deployment stage until every one is online.
"""

from __future__ import annotations

import os
import time

from ocpplab import OcpplabSDK
from ocpplab.types import VirtualLocationChargerItem, VirtualLocationCoordinates

IDENTITIES = ["DEMO-CP-001", "DEMO-CP-002"]


def main() -> None:
    # Defaults to https://api.ocpplab.io; pass base_url= for another host.
    client = OcpplabSDK(token=os.environ["OCPPLAB_TOKEN"])
    accepted = client.evcharger.location.create(
        name="Demo hub",
        address="1 Parvis de la Defense",
        city="Puteaux",
        country="FRA",
        coordinates=VirtualLocationCoordinates(lat=48.892, lng=2.238),
        chargers=[
            VirtualLocationChargerItem(
                identity=identity,
                brand_slug="wallbox",
                model="wallbox-pulsar-plus",
                connector_type="Type2",
                ws_url=os.environ["CSMS_WS_URL"],
            )
            for identity in IDENTITIES
        ],
    )
    print(f"location {accepted.location_id}: {accepted.detail}")

    deadline = time.monotonic() + 600
    while True:
        chargers = client.evcharger.deployment_runtime_ops.status(
            identity=IDENTITIES
        ).items
        for charger in chargers:
            print(charger.identity, charger.stage, charger.outcome, charger.hint or "")
        if chargers and all(charger.stage == "online" for charger in chargers):
            return
        if any(charger.outcome in ("failed", "stuck") for charger in chargers):
            raise SystemExit("a charger failed to deploy; see the hint above")
        if time.monotonic() > deadline:
            raise SystemExit("chargers were not online after 10 minutes")
        time.sleep(5)


if __name__ == "__main__":
    main()

```

#### Run it

**`TypeScript`**

```bash TypeScript
npx tsx quickstart.ts
```

**`Python`**

```bash Python
python quickstart.py
```

Each poll prints one line per charger, for example `DEMO-CP-001 online succeeded`. Your CSMS now sees two chargers boot.

## Why it polls

Creating a location returns **202 Accepted** at once and deploys the chargers in the background. The script calls `deploymentRuntimeOps.status` (`deployment_runtime_ops.status` in Python) every 5 seconds until each charger's `stage` is `online`. If a charger's `outcome` is `failed` or `stuck`, its `hint` says why. See [Long-running operations](/get-started/guides/long-running-operations).

## Next steps

* Choose another charger model: `evcharger.catalog.listBrands()`, then `listModels(brand_slug)`.
* Start from one of the 20 ready-made location templates: `evcharger.templates.list()`.
* Run a charging session: [Plug, charge and unplug](/get-started/guides/plug-charge-unplug).