> ## Documentation Index
> Fetch the complete documentation index at: https://dynamo-csms.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Charge Points API — Register and Manage Chargers

> Register, configure, and manage EV charge points via the Installer and CPO APIs. Covers certificate management, config templates, and connection testing.

Dynamo CSMS provides two charge point management surfaces: the **Installer API** for field technicians registering and configuring hardware on-site, and the **CPO API** for Charge Point Operators managing their fleet programmatically. Both surfaces require authentication — installer endpoints use a JWT from the installer login flow, while CPO endpoints use an organization API key.

***

## Installer charge points

### Register a charge point

`POST /api/v1/installer/charge-points`

Registers a new charge point with Dynamo CSMS and returns the configuration needed to connect the hardware to the platform via OCPP.

<ParamField body="charge_point_id" type="string" required>
  Unique identifier for the charge point, typically matching the hardware serial or OCPP identity. Maximum 48 characters, alphanumeric and hyphens only.
</ParamField>

<ParamField body="model" type="string" required>
  Hardware model name (e.g. `"ABB Terra AC W22-G5"`).
</ParamField>

<ParamField body="vendor" type="string" required>
  Hardware manufacturer name (e.g. `"ABB"`).
</ParamField>

<ParamField body="serial_number" type="string" required>
  Physical serial number printed on the unit.
</ParamField>

<ParamField body="project_id" type="string" required>
  The project this charge point belongs to. Projects group charge points by site or deployment.
</ParamField>

<ParamField body="location" type="object">
  Optional GPS coordinates for the charge point.

  <Expandable title="location fields">
    <ParamField body="location.latitude" type="number">
      Decimal latitude (e.g. `51.5074`).
    </ParamField>

    <ParamField body="location.longitude" type="number">
      Decimal longitude (e.g. `-0.1278`).
    </ParamField>

    <ParamField body="location.address" type="string">
      Human-readable address for display purposes.
    </ParamField>
  </Expandable>
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.dynamo-csms.com/api/v1/installer/charge-points \
    -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "charge_point_id": "CP-SITE42-001",
      "model": "ABB Terra AC W22-G5",
      "vendor": "ABB",
      "serial_number": "SN-20240310-001",
      "project_id": "proj_8c2f4e1a",
      "location": {
        "latitude": 51.5074,
        "longitude": -0.1278,
        "address": "10 Downing St, London, UK"
      }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.dynamo-csms.com/api/v1/installer/charge-points",
      headers={"Authorization": "Bearer INSTALLER_ACCESS_TOKEN"},
      json={
          "charge_point_id": "CP-SITE42-001",
          "model": "ABB Terra AC W22-G5",
          "vendor": "ABB",
          "serial_number": "SN-20240310-001",
          "project_id": "proj_8c2f4e1a",
      },
  )
  print(response.json())
  ```
</CodeGroup>

**Response `201 Created`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "project_id": "proj_8c2f4e1a",
  "model": "ABB Terra AC W22-G5",
  "vendor": "ABB",
  "serial_number": "SN-20240310-001",
  "status": "registered",
  "ocpp_endpoint": "wss://ocpp.dynamo-csms.com/ocpp16/CP-SITE42-001",
  "registered_at": "2024-03-10T14:00:00Z",
  "location": {
    "latitude": 51.5074,
    "longitude": -0.1278,
    "address": "10 Downing St, London, UK"
  }
}
```

<ResponseField name="ocpp_endpoint" type="string">
  The WebSocket URL to configure on the charge point hardware for OCPP connectivity.
</ResponseField>

<ResponseField name="status" type="string">
  Initial status is always `registered`. Progresses through `configured`, `connected`, and `commissioned`.
</ResponseField>

***

### List charge points

`GET /api/v1/installer/charge-points`

Returns all charge points registered by the authenticated installer.

<ParamField query="project_id" type="string">
  Filter by project ID.
</ParamField>

<ParamField query="status" type="string">
  Filter by status. One of: `registered`, `configured`, `connected`, `commissioned`, `offline`.
</ParamField>

<ParamField query="page" type="integer">
  Page number for pagination (default: 1).
</ParamField>

<ParamField query="per_page" type="integer">
  Results per page (default: 20, max: 100).
</ParamField>

```bash theme={null}
curl "https://api.dynamo-csms.com/api/v1/installer/charge-points?project_id=proj_8c2f4e1a&status=connected" \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_points": [
    {
      "charge_point_id": "CP-SITE42-001",
      "model": "ABB Terra AC W22-G5",
      "vendor": "ABB",
      "status": "connected",
      "project_id": "proj_8c2f4e1a",
      "last_seen_at": "2024-03-10T14:55:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20
}
```

***

### Get charge point

`GET /api/v1/installer/charge-points/{charge_point_id}`

Returns full details for a single charge point.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001 \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "model": "ABB Terra AC W22-G5",
  "vendor": "ABB",
  "serial_number": "SN-20240310-001",
  "project_id": "proj_8c2f4e1a",
  "status": "commissioned",
  "ocpp_endpoint": "wss://ocpp.dynamo-csms.com/ocpp16/CP-SITE42-001",
  "identity_verified": true,
  "tls_enabled": true,
  "commissioned_at": "2024-03-10T16:30:00Z",
  "last_seen_at": "2024-03-10T17:02:00Z",
  "location": {
    "latitude": 51.5074,
    "longitude": -0.1278,
    "address": "10 Downing St, London, UK"
  }
}
```

***

### Update charge point

`PUT /api/v1/installer/charge-points/{charge_point_id}`

Updates metadata for a registered charge point. You cannot change `charge_point_id` or `serial_number` after registration.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

<ParamField body="model" type="string">
  Updated hardware model name.
</ParamField>

<ParamField body="vendor" type="string">
  Updated vendor name.
</ParamField>

<ParamField body="project_id" type="string">
  Move the charge point to a different project.
</ParamField>

<ParamField body="location" type="object">
  Updated location data.
</ParamField>

```bash theme={null}
curl -X PUT https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001 \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "location": {
      "latitude": 51.5080,
      "longitude": -0.1290,
      "address": "12 Downing St, London, UK"
    }
  }'
```

**Response `200 OK`** — returns the full updated charge point object.

***

### Delete charge point

`DELETE /api/v1/installer/charge-points/{charge_point_id}`

Removes a charge point from Dynamo CSMS. The charge point must be offline and not currently in an active session. Historical session and billing data is retained.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

```bash theme={null}
curl -X DELETE https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001 \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `204 No Content`**

***

## Certificate management

### Generate TLS certificate

`POST /api/v1/installer/charge-points/{charge_point_id}/certificates/generate`

Generates a TLS client certificate for the charge point. Install this certificate on the hardware to enable mutual TLS authentication on the OCPP WebSocket connection.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

<ParamField body="validity_days" type="integer">
  Certificate validity period in days (default: 365, max: 1095).
</ParamField>

```bash theme={null}
curl -X POST https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/certificates/generate \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"validity_days": 365}'
```

**Response `201 Created`**

```json theme={null}
{
  "certificate_id": "cert_3b7f9a2c",
  "charge_point_id": "CP-SITE42-001",
  "certificate_pem": "-----BEGIN CERTIFICATE-----\nMIIDazCCAlOgAwIBAgI...\n-----END CERTIFICATE-----",
  "private_key_pem": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0...\n-----END PRIVATE KEY-----",
  "ca_certificate_pem": "-----BEGIN CERTIFICATE-----\nMIIDqTCCApGgAwIBAgI...\n-----END CERTIFICATE-----",
  "issued_at": "2024-03-10T14:05:00Z",
  "expires_at": "2025-03-10T14:05:00Z"
}
```

The `private_key_pem` is returned **once only** — store it securely alongside the certificate.

***

### List certificates

`GET /api/v1/installer/charge-points/{charge_point_id}/certificates`

Lists all certificates issued for a charge point, including expired ones.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/certificates \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "certificates": [
    {
      "certificate_id": "cert_3b7f9a2c",
      "status": "active",
      "issued_at": "2024-03-10T14:05:00Z",
      "expires_at": "2025-03-10T14:05:00Z"
    }
  ]
}
```

***

## Configuration management

### Get config template

`GET /api/v1/installer/charge-points/{charge_point_id}/config/template`

Returns the default OCPP configuration template for this charge point's model. Use it as a starting point before customizing.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/config/template \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "template_id": "tpl_abb_terra_ac_w22",
  "model": "ABB Terra AC W22-G5",
  "parameters": {
    "HeartbeatInterval": 60,
    "MeterValueSampleInterval": 60,
    "ConnectionTimeOut": 60,
    "AuthorizationCacheEnabled": true,
    "LocalAuthListEnabled": true,
    "AllowOfflineTxForUnknownId": false,
    "StopTransactionOnEVSideDisconnect": true
  }
}
```

***

### Customize configuration

`POST /api/v1/installer/charge-points/{charge_point_id}/config/customize`

Saves a custom OCPP configuration for this charge point, overriding template defaults.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

<ParamField body="parameters" type="object" required>
  Key-value map of OCPP configuration keys to set. Only include the keys you want to override.
</ParamField>

```bash theme={null}
curl -X POST https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/config/customize \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "parameters": {
      "HeartbeatInterval": 30,
      "MeterValueSampleInterval": 30,
      "AuthorizationCacheEnabled": false
    }
  }'
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "message": "Configuration saved. Apply it to the hardware using the download endpoint.",
  "updated_parameters": ["HeartbeatInterval", "MeterValueSampleInterval", "AuthorizationCacheEnabled"]
}
```

***

### Download configuration

`GET /api/v1/installer/charge-points/{charge_point_id}/config/download`

Downloads the final merged configuration (template + customizations) as a JSON file ready to upload to the charge point hardware.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/config/download \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN" \
  -o CP-SITE42-001-config.json
```

**Response `200 OK`** — returns `application/json` with the full configuration object.

***

## Connection testing

### Test connection

`POST /api/v1/installer/charge-points/{charge_point_id}/test-connection`

Initiates a connection test by sending a ping to the charge point over OCPP. Use this to verify network reachability before commissioning.

```bash theme={null}
curl -X POST https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/test-connection \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "reachable": true,
  "latency_ms": 42,
  "ocpp_version": "1.6",
  "tested_at": "2024-03-10T14:20:00Z"
}
```

***

### Get connection status

`GET /api/v1/installer/charge-points/{charge_point_id}/connection-status`

Returns the current real-time connection status of the charge point.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/connection-status \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "connected": true,
  "last_heartbeat_at": "2024-03-10T14:58:30Z",
  "websocket_state": "open",
  "ip_address": "203.0.113.42"
}
```

***

### Commission charge point

`POST /api/v1/installer/charge-points/{charge_point_id}/commission`

Marks a charge point as commissioned and live. This transitions the charge point from installer-mode to production operation. Requires the charge point to be connected and all configuration steps to be complete.

```bash theme={null}
curl -X POST https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/commission \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "status": "commissioned",
  "commissioned_at": "2024-03-10T16:30:00Z",
  "message": "Charge point is now live and available for EV drivers."
}
```

***

### Get charge point status

`GET /api/v1/installer/charge-points/{charge_point_id}/status`

Returns the current operational status of a charge point.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/installer/charge-points/CP-SITE42-001/status \
  -H "Authorization: Bearer INSTALLER_ACCESS_TOKEN"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CP-SITE42-001",
  "operational_status": "Available",
  "connectors": [
    {
      "connector_id": 1,
      "status": "Available",
      "error_code": "NoError"
    },
    {
      "connector_id": 2,
      "status": "Charging",
      "error_code": "NoError",
      "active_transaction_id": "txn_9a3c1b4d"
    }
  ],
  "last_updated_at": "2024-03-10T17:05:00Z"
}
```

***

## CPO charge points

CPO (Charge Point Operator) endpoints use an organization API key with the `write:charge_points` or `read:charge_points` scope.

### Create charge point (CPO)

`POST /api/v1/chargepoints`

Creates a charge point record at the CPO level, for operators managing charge points without going through the installer workflow.

<ParamField body="charge_point_id" type="string" required>
  Unique charge point identifier.
</ParamField>

<ParamField body="name" type="string" required>
  Display name for the charge point.
</ParamField>

<ParamField body="latitude" type="number" required>
  GPS latitude.
</ParamField>

<ParamField body="longitude" type="number" required>
  GPS longitude.
</ParamField>

<ParamField body="address" type="string" required>
  Physical address of the charge point.
</ParamField>

<ParamField body="connector_count" type="integer" required>
  Number of connectors on this unit.
</ParamField>

<ParamField body="max_power_kw" type="number" required>
  Maximum charging power per connector in kilowatts.
</ParamField>

```bash theme={null}
curl -X POST https://api.dynamo-csms.com/api/v1/chargepoints \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "charge_point_id": "CPO-FLEET-099",
    "name": "Car Park Level 2 - Bay 3",
    "latitude": 51.5074,
    "longitude": -0.1278,
    "address": "1 Example St, London, UK",
    "connector_count": 2,
    "max_power_kw": 22.0
  }'
```

**Response `201 Created`**

```json theme={null}
{
  "charge_point_id": "CPO-FLEET-099",
  "name": "Car Park Level 2 - Bay 3",
  "status": "offline",
  "created_at": "2024-03-10T14:00:00Z"
}
```

***

### Update charge point (CPO)

`PATCH /api/v1/chargepoints/{charge_point_id}`

Partially updates a CPO charge point. Only include fields you want to change.

<ParamField path="charge_point_id" type="string" required>
  The charge point's unique identifier.
</ParamField>

<ParamField body="name" type="string">
  Updated display name.
</ParamField>

<ParamField body="address" type="string">
  Updated address.
</ParamField>

<ParamField body="max_power_kw" type="number">
  Updated maximum power in kilowatts.
</ParamField>

```bash theme={null}
curl -X PATCH https://api.dynamo-csms.com/api/v1/chargepoints/CPO-FLEET-099 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Car Park Level 2 - Bay 3 (Fast)"}'
```

**Response `200 OK`** — returns the full updated charge point object.

***

### Search charge points by proximity

`GET /api/v1/chargepoints/search`

Returns charge points near a given GPS coordinate, ordered by distance.

<ParamField query="latitude" type="number" required>
  Center latitude for the proximity search.
</ParamField>

<ParamField query="longitude" type="number" required>
  Center longitude for the proximity search.
</ParamField>

<ParamField query="radius_km" type="number">
  Search radius in kilometers (default: 5, max: 50).
</ParamField>

<ParamField query="status" type="string">
  Filter by connector status: `available`, `occupied`, `offline`.
</ParamField>

```bash theme={null}
curl "https://api.dynamo-csms.com/api/v1/chargepoints/search?latitude=51.5074&longitude=-0.1278&radius_km=2&status=available" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_points": [
    {
      "charge_point_id": "CPO-FLEET-099",
      "name": "Car Park Level 2 - Bay 3",
      "distance_km": 0.3,
      "status": "available",
      "available_connectors": 2,
      "max_power_kw": 22.0,
      "latitude": 51.5074,
      "longitude": -0.1278
    }
  ],
  "total": 1
}
```

***

### Get CPO charge point status

`GET /api/v1/chargepoints/{charge_point_id}/status`

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/chargepoints/CPO-FLEET-099/status \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CPO-FLEET-099",
  "online": true,
  "operational_status": "Available",
  "last_heartbeat_at": "2024-03-10T17:00:00Z"
}
```

***

### List connectors

`GET /api/v1/chargepoints/{charge_point_id}/connectors`

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/chargepoints/CPO-FLEET-099/connectors \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CPO-FLEET-099",
  "connectors": [
    {
      "connector_id": 1,
      "type": "Type2",
      "max_power_kw": 22.0,
      "status": "Available"
    },
    {
      "connector_id": 2,
      "type": "CCS2",
      "max_power_kw": 50.0,
      "status": "Charging"
    }
  ]
}
```

***

### Get tariff

`GET /api/v1/chargepoints/{charge_point_id}/tariff`

Returns the current pricing tariff applied to this charge point.

```bash theme={null}
curl https://api.dynamo-csms.com/api/v1/chargepoints/CPO-FLEET-099/tariff \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response `200 OK`**

```json theme={null}
{
  "charge_point_id": "CPO-FLEET-099",
  "tariff": {
    "currency": "GBP",
    "price_per_kwh": 0.35,
    "session_fee": 0.50,
    "idle_fee_per_minute": 0.05,
    "free_idle_minutes": 10,
    "updated_at": "2024-02-01T00:00:00Z"
  }
}
```

***

### Update tariff

`PUT /api/v1/chargepoints/{charge_point_id}/tariff`

Sets or replaces the tariff for a charge point. Requires `write:charge_points` scope.

<ParamField body="currency" type="string" required>
  ISO 4217 currency code (e.g. `"GBP"`, `"EUR"`, `"USD"`).
</ParamField>

<ParamField body="price_per_kwh" type="number" required>
  Price per kilowatt-hour.
</ParamField>

<ParamField body="session_fee" type="number">
  Flat fee charged at session start.
</ParamField>

<ParamField body="idle_fee_per_minute" type="number">
  Per-minute fee charged when a vehicle remains plugged in after charging completes.
</ParamField>

<ParamField body="free_idle_minutes" type="integer">
  Number of idle minutes allowed before idle fees apply.
</ParamField>

```bash theme={null}
curl -X PUT https://api.dynamo-csms.com/api/v1/chargepoints/CPO-FLEET-099/tariff \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "GBP",
    "price_per_kwh": 0.38,
    "session_fee": 0.50,
    "idle_fee_per_minute": 0.05,
    "free_idle_minutes": 10
  }'
```

**Response `200 OK`** — returns the updated tariff object.

***

### Search public chargers (no auth)

`GET /api/v1/public/chargers`

Returns publicly listed charge points. No authentication required. Suitable for driver-facing apps and maps.

<ParamField query="latitude" type="number" required>
  Center latitude.
</ParamField>

<ParamField query="longitude" type="number" required>
  Center longitude.
</ParamField>

<ParamField query="radius_km" type="number">
  Search radius in kilometers (default: 5, max: 50).
</ParamField>

```bash theme={null}
curl "https://api.dynamo-csms.com/api/v1/public/chargers?latitude=51.5074&longitude=-0.1278&radius_km=1"
```

**Response `200 OK`**

```json theme={null}
{
  "chargers": [
    {
      "charge_point_id": "CPO-FLEET-099",
      "name": "Car Park Level 2 - Bay 3",
      "latitude": 51.5074,
      "longitude": -0.1278,
      "address": "1 Example St, London, UK",
      "distance_km": 0.3,
      "available_connectors": 2,
      "total_connectors": 2,
      "max_power_kw": 22.0,
      "price_per_kwh": 0.38,
      "currency": "GBP"
    }
  ],
  "total": 1
}
```

***

## Error responses

| Status | Code               | Meaning                                             |
| ------ | ------------------ | --------------------------------------------------- |
| `400`  | `validation_error` | Required field missing or invalid format            |
| `401`  | `unauthorized`     | Missing or expired token                            |
| `403`  | `forbidden`        | Insufficient scope for this operation               |
| `404`  | `not_found`        | Charge point ID does not exist                      |
| `409`  | `already_exists`   | A charge point with this ID is already registered   |
| `422`  | `active_session`   | Cannot delete a charge point with an active session |
| `422`  | `not_connected`    | Operation requires the charge point to be online    |
