# Get DATEX II v3 AFIR energy infrastructure statuses
Source: https://docs.spirii.com/api-reference/afir/get-datex-ii-v3-afir-energy-infrastructure-statuses
/openapi/integration-api-v2/openapi.yaml get /v2/afir/energy-infrastructure-statuses
# Get DATEX II v3 AFIR energy infrastructure tables
Source: https://docs.spirii.com/api-reference/afir/get-datex-ii-v3-afir-energy-infrastructure-tables
/openapi/integration-api-v2/openapi.yaml get /v2/afir/energy-infrastructure-tables
# Create app user
Source: https://docs.spirii.com/api-reference/app-users/create-app-user
/openapi/integration-api-v2/openapi.yaml post /v2/app-users
Creates an app user. Only available to operators with a whitelabel app.
# Get a list of app users
Source: https://docs.spirii.com/api-reference/app-users/get-a-list-of-app-users
/openapi/integration-api-v2/openapi.yaml get /v2/app-users
Retrieves a paginated list of app users. Only available to operators with a whitelabel app.
# Get app user by id
Source: https://docs.spirii.com/api-reference/app-users/get-app-user-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/app-users/{id}
Retrieves an app user by id. Only available to operators with a whitelabel app.
# Retrieve a app users
Source: https://docs.spirii.com/api-reference/app-users/retrieve-a-app-users
/openapi/integrations-api/openapi.yml get /app-users/{id}
# Retrieve a list of app users
Source: https://docs.spirii.com/api-reference/app-users/retrieve-a-list-of-app-users
/openapi/integrations-api/openapi.yml get /app-users
# Update app user
Source: https://docs.spirii.com/api-reference/app-users/update-app-user
/openapi/integration-api-v2/openapi.yaml put /v2/app-users/{id}
Updates an app user. Only available to operators with a whitelabel app.
# Fetches a list of audit logs.
Source: https://docs.spirii.com/api-reference/audit-logs/fetches-a-list-of-audit-logs
/openapi/integration-api-v2/openapi.yaml get /v2/audit-logs
# Get a list of CDRs
Source: https://docs.spirii.com/api-reference/charge-records-v2/get-a-list-of-cdrs
/openapi/integration-api-v2/openapi.yaml get /v2/charge-records
# Get a single Charge Record
Source: https://docs.spirii.com/api-reference/charge-records-v2/get-a-single-charge-record
/openapi/integration-api-v2/openapi.yaml get /v2/charge-records/{id}
Get one Charge Record by given ID.
# Retrieve complete charge record data by ID
Source: https://docs.spirii.com/api-reference/charge-records/retrieve-complete-charge-record-data-by-id
/openapi/integrations-api/openapi.yml get /v1/charge-records/{id}
# Retrieve the charge records data
Source: https://docs.spirii.com/api-reference/charge-records/retrieve-the-charge-records-data
/openapi/integrations-api/openapi.yml get /v1/charge-records
# Creates a new charge box.
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/creates-a-new-charge-box
/openapi/integration-api-v2/openapi.yaml post /v2/chargeboxes
# Deletes a charge box. This operation cannot be undone.
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/deletes-a-charge-box-this-operation-cannot-be-undone
/openapi/integration-api-v2/openapi.yaml delete /v2/chargeboxes/{id}
# Fetches a list of charge boxes
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/fetches-a-list-of-charge-boxes
/openapi/integration-api-v2/openapi.yaml get /v2/chargeboxes
# Fetches a list of supported charge box models
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/fetches-a-list-of-supported-charge-box-models
/openapi/integration-api-v2/openapi.yaml get /v2/chargeboxes/models
# Fetches a single charge box.
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/fetches-a-single-charge-box
/openapi/integration-api-v2/openapi.yaml get /v2/chargeboxes/{id}
# Performs a hard or soft reset on a charge box.
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/performs-a-hard-or-soft-reset-on-a-charge-box
/openapi/integration-api-v2/openapi.yaml post /v2/chargeboxes/{id}/reset
Please be aware that resetting may cause temporary downtime, depending on the charge box model, and plan usage accordingly.
# Reboots a charge box. (Alias for soft reset)
Source: https://docs.spirii.com/api-reference/chargeboxes-v2/reboots-a-charge-box-alias-for-soft-reset
/openapi/integration-api-v2/openapi.yaml post /v2/chargeboxes/{id}/reboot
Please be aware that rebooting may cause temporary downtime, depending on the charge box model, and plan usage accordingly.
# Create a new customer
Source: https://docs.spirii.com/api-reference/customer-v2/create-a-new-customer
/openapi/integration-api-v2/openapi.yaml post /v2/customers
Creates a new customer record in the system.
# Delete a customer
Source: https://docs.spirii.com/api-reference/customer-v2/delete-a-customer
/openapi/integration-api-v2/openapi.yaml delete /v2/customers/{id}
Deletes a customer record in the system.
# Get one customer by id
Source: https://docs.spirii.com/api-reference/customer-v2/get-one-customer-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/customers/{id}
Retrieves a customer by their unique identifier.
# Get v2customers
Source: https://docs.spirii.com/api-reference/customer-v2/get-v2customers
/openapi/integration-api-v2/openapi.yaml get /v2/customers
Retrieves a paginated list of customers based on the provided filter criteria.
# Update a customer
Source: https://docs.spirii.com/api-reference/customer-v2/update-a-customer
/openapi/integration-api-v2/openapi.yaml put /v2/customers/{id}
Updates a customer record in the system.
# Deregister an EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/deregister-an-emsp-identity
/openapi/emsp-tenant/openapi.yaml delete /emsp/v1/tenant/emsp-identities/{emsp_identity_id}
Removes a roaming identity from your organization. Two things to know first, your organization must always keep at least one identity, so you can't remove the last one, and you can't remove an identity that's still in use. Sort those out first, then remove it.
# Deregister an EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/deregister-an-emsp-identity-1
/openapi/emsp-tenant/openapi.yaml delete /emsp/v1/tenant/emp-identities/{emsp_identity_id}
Removes a roaming identity from your organization. Two things to know first, your organization must always keep at least one identity, so you can't remove the last one, and you can't remove an identity that's still in use. Sort those out first, then remove it.
# Get EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/get-emsp-identity
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/emsp-identities/{emsp_identity_id}
Returns a single roaming identity by its ID, including its current status.
# Get EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/get-emsp-identity-1
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/emp-identities/{emsp_identity_id}
Returns a single roaming identity by its ID, including its current status.
# List EMSP identities
Source: https://docs.spirii.com/api-reference/emsp-identity/list-emsp-identities
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/emsp-identities
Lists all of the roaming identities registered to your organization. Every organization has at least one (set up by Spirii), and you can register more — for example to keep different brands or regions separate.
# List EMSP identities
Source: https://docs.spirii.com/api-reference/emsp-identity/list-emsp-identities-1
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/emp-identities
Lists all of the roaming identities registered to your organization. Every organization has at least one (set up by Spirii), and you can register more — for example to keep different brands or regions separate.
# Register an EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/register-an-emsp-identity
/openapi/emsp-tenant/openapi.yaml post /emsp/v1/tenant/emsp-identities
Registers a new roaming identity for your organization. You'll need the country and the three-character party code, and you can optionally list one or more roaming standards it uses (OCPI, OICP). To stay safe if a request is accidentally sent twice, you also include a one-off reference you generate yourself (an idempotency key) — Spirii uses it to return the original result instead of creating a duplicate.
# Register an EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/register-an-emsp-identity-1
/openapi/emsp-tenant/openapi.yaml post /emsp/v1/tenant/emp-identities
Registers a new roaming identity for your organization. You'll need the country and the three-character party code, and you can optionally list one or more roaming standards it uses (OCPI, OICP). To stay safe if a request is accidentally sent twice, you also include a one-off reference you generate yourself (an idempotency key) — Spirii uses it to return the original result instead of creating a duplicate.
# Update EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/update-emsp-identity
/openapi/emsp-tenant/openapi.yaml put /emsp/v1/tenant/emsp-identities/{emsp_identity_id}
Updates the details of one of your roaming identities — things like its label or its contact information. Its ID and its status are managed by Spirii and can't be changed here. As with registering, you include a one-off reference (an "idempotency key") so a repeated request isn't applied twice.
# Update EMSP identity
Source: https://docs.spirii.com/api-reference/emsp-identity/update-emsp-identity-1
/openapi/emsp-tenant/openapi.yaml put /emsp/v1/tenant/emp-identities/{emsp_identity_id}
Updates the details of one of your roaming identities — things like its label or its contact information. Its ID and its status are managed by Spirii and can't be changed here. As with registering, you include a one-off reference (an "idempotency key") so a repeated request isn't applied twice.
# Authentication
Source: https://docs.spirii.com/api-reference/emsp/authentication
Exchange your client credentials for an access token, and request the scopes your integration needs.
The eMSP API authenticates with OAuth2 client credentials. You exchange a client ID and secret for a short-lived access token, then send that token as a bearer token on every request.
This is different from the rest of the Spirii API, which uses a long-lived API key. If you're integrating against those endpoints, see [Authentication](/developers/authentication) instead.
## How access is structured
Four things sit between your company and an endpoint.
```mermaid theme={null}
flowchart TD
O("Organisation
(your company)") --> W("Workspace
(your eMSP tenant)")
W --> C("Credential
(ID and secret)")
C --> S("Scopes
(what it may do)")
```
Your **organisation** is your company as Spirii knows it. Inside it, a **workspace** groups credentials; on the eMSP API a workspace is a tenant, so the workspace your credential belongs to decides whose networks, locations and webhooks you're working with. A **credential** is one OAuth2 client: a client ID and a secret. The **scopes** attached to that credential set the capabilities it can ask for.
You never pass an organisation, workspace or tenant ID in a request. All three travel inside the access token, and Spirii resolves them from it.
## Get your credentials
Spirii provisions credentials during onboarding. Your Spirii contact sends you a client ID, a client secret, and the list of scopes attached to the credential.
Store the secret in a secret manager or an environment variable, never in source control. The [security best practices](/developers/authentication#security-best-practices) for API keys apply here unchanged.
When your integration grows into a capability the credential doesn't cover, ask Spirii to attach the scope. That's a grant against your existing credential, not a new credential and not a code change on your side.
## Get an access token
Post your credentials to the token endpoint of Spirii's `public-api` realm, naming the scopes you want the token to carry:
```bash theme={null}
curl -X POST 'https://auth.spirii.dk/realms/public-api/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d "client_id=$SPIRII_CLIENT_ID" \
-d "client_secret=$SPIRII_CLIENT_SECRET" \
--data-urlencode 'scope=emsp:networks:read emsp:locations:read'
```
Scope values are space-separated, so they have to be URL-encoded. With `curl` that means `--data-urlencode` rather than `-d`.
The response carries four fields worth reading:
| Field | What it's for |
| - | - |
| `access_token` | The token you send as a bearer token |
| `expires_in` | Seconds until the token expires. Access tokens live for 300 seconds |
| `token_type` | Always `Bearer` |
| `scope` | The scopes the token actually carries. Check this matches what you asked for |
A token is good for five minutes. Cache it and fetch a new one shortly before it expires. Requesting a token per API call works, but it adds a round trip to every request for no benefit.
## Scopes
A scope attached to your credential makes it *allowed* to request that capability. It does not put the capability in every token. The token carries a scope only when you name it in the `scope` parameter. Two things follow from that, and both look like a broken integration when you meet them for the first time.
**Omit the `scope` parameter and the token request still succeeds.** You get a valid token carrying none of your capabilities, and every eMSP endpoint answers `403`. **Request a scope that isn't attached to your credential and the whole token request fails** with `invalid_scope`, so a single typo costs you the token rather than that one scope.
These are the scopes available across the eMSP API:
| API | Scope | Grants |
| - | - | - |
| Tenants | `emsp:tenants:read` | View tenant profile, EMP identities, and webhooks |
| Tenants | `emsp:tenants:write` | Manage tenant profile, EMP identities, and webhooks |
| Networks | `emsp:networks:read` | View network and access control configuration |
| Networks | `emsp:networks:write` | Create, update and delete SUB networks, and manage access rules |
| Networks | `emsp:networks:publish` | Publish and drain networks |
| Networks | `emsp:networks:subscribe` | Attach to another tenant's published base network as a consumer |
| Locations | `emsp:locations:read` | Search and view locations, EVSEs and connectors |
| Tokens | `emsp:tokens:read` | Read tokens, token history, token groups and their network assignments |
| Tokens | `emsp:tokens:write` | Provision, update and change the lifecycle of tokens; create and manage token groups. Also grants everything `emsp:tokens:read` does |
| Webhooks | `emsp:webhooks:read` | View webhook subscriptions and delivery history |
| Webhooks | `emsp:webhooks:write` | Create, update, pause and delete webhook subscriptions |
Ask for the scopes a given token needs rather than everything attached to the credential. A token minted for a nightly location sync has no reason to carry `emsp:networks:publish`, and keeping it out means a leaked token can't be used to publish anything.
Changing what's attached to a credential doesn't reach tokens already issued. After Spirii attaches a scope, request a new token to pick it up.
## Authorize a request
Send the access token in the `Authorization` header, prefixed with `Bearer`:
```bash theme={null}
curl 'https://api.spirii.com/emsp/v1/locations' \
-H "Authorization: Bearer $ACCESS_TOKEN"
```
Every eMSP endpoint sits under `https://api.spirii.com/emsp/v1`.
## What's in the token
The access token is a signed JWT issued by `https://auth.spirii.dk/realms/public-api` using RS256. Decode it and you'll find the claims Spirii uses to identify you:
| Claim | What it holds |
| - | - |
| `azp` | Your client ID |
| `organisation_id` | The organisation the credential belongs to |
| `workspace_id` | The workspace, which is your eMSP tenant |
| `credential_id` | The credential itself, useful when you hold several |
| `scope` | The granted scopes, space-separated |
| `exp` | Expiry, as a Unix timestamp |
Reading these claims helps when you're working out why a call was refused. Spirii verifies the token and derives your identity from it on every request, so treat the claims as diagnostic information rather than something your own code makes access decisions from.
Alongside your scopes, `scope` also carries Keycloak's built-in defaults such as `email` and `profile`. They grant nothing on the eMSP API and are safe to ignore.
## Errors
| Response | Returned by | Cause |
| - | - | - |
| `invalid_client` | Token endpoint | Wrong client ID or secret, or the credential has been disabled |
| `invalid_scope` | Token endpoint | A requested scope isn't attached to the credential, or is misspelled |
| `401` Unauthorized | eMSP API | The `Authorization` header is missing or malformed, or the token has expired or wasn't issued by Spirii |
| `403` Forbidden | eMSP API | The token is valid but carries no scope covering this endpoint. Request a new token naming the scope you need |
| `403` Forbidden | eMSP API | The request presented an `x-spirii-*` header. Spirii sets those from your token; sending them yourself is rejected at the edge |
## Rotate and revoke
Ask Spirii to rotate the secret and you get a new one immediately; the old secret stops working for new token requests at the same moment.
Tokens already issued are a different matter. A token stays valid for its full 300 seconds, and Spirii caches the result of verifying it for up to 300 seconds more, so a credential can keep working for roughly ten minutes after it's rotated or disabled. Neither action is an instant kill switch; plan rotations and revocations around that window.
To rotate without downtime: take the new secret, fetch a token with it to confirm it works, roll it into your integration, and drop the old one.
## Related
The four Spirii APIs, their path prefixes, and where to start.
The status codes the API returns and how to handle them.
The request limits and how to stay under them.
# Webhook delivery
Source: https://docs.spirii.com/api-reference/emsp/webhook-delivery
Verify the signature on an incoming delivery, respond correctly, and keep your subscription healthy.
When an event you've subscribed to occurs, Spirii sends it to your endpoint as a signed JSON POST. Every delivery carries the same envelope and the same three signing headers, whatever the event type.
Subscriptions themselves are managed through the Webhooks endpoints. This page covers what arrives afterwards.
## Your endpoint
Your endpoint has to be reachable over **HTTPS** at a **publicly resolvable address**. Spirii resolves the hostname before each delivery and refuses any that points at a private, loopback, link-local, metadata or otherwise reserved address, on both IPv4 and IPv6. The check runs against the resolved addresses rather than the hostname, so a public name pointing at an internal IP is refused too.
A consequence worth knowing during development: `localhost`, `127.0.0.1` and private-range addresses can never receive deliveries. Use a public tunnel endpoint while you build.
## The delivery request
Each delivery is a `POST` with a JSON body. Spirii waits **10 seconds** for your response.
| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `X-Signature` | `sha256=` followed by the hex HMAC of the body. See [Verify the signature](#verify-the-signature) |
| `X-Webhook-Timestamp` | When the delivery was signed, as a Unix timestamp in seconds |
| `X-Webhook-Id` | The event id, repeated from `event_id` in the body |
Any custom headers you configured on the subscription are sent alongside these. The three signing headers always take precedence, so a custom header cannot overwrite them.
The body is the same envelope for every event type:
| Field | What it holds |
| - | - |
| `event_id` | Unique id for this event. Stable across retries of the same event |
| `type` | The event type, such as `location.added` |
| `api_version` | The payload version this subscription is pinned to |
| `occurred_at` | When the event happened on the platform, ISO 8601 |
| `published_at` | When Spirii published it for delivery, ISO 8601 |
| `data` | The event body, whose shape is defined by the event type |
```json theme={null}
{
"event_id": "0199b3c7-4f2a-7a1e-9c3d-5b8e2f1a6d04",
"type": "location.added",
"api_version": "v1",
"occurred_at": "2026-09-18T09:12:04.318Z",
"published_at": "2026-09-18T09:12:04.492Z",
"data": {}
}
```
`data` is shown empty here because its contents differ per event type. Fetch the schema for the types you subscribe to from `GET /emsp/v1/webhooks/event_types/{type}`, which returns the versions available and the latest one. Those schemas are served live, so read them from the API rather than copying them into your code.
## Verify the signature
Spirii signs the timestamp and the body together, so a captured delivery can't be replayed later with a fresh timestamp:
```
X-Signature: sha256=HMAC_SHA256(secret, "{X-Webhook-Timestamp}.{raw body}")
```
The secret is the one returned when you created the subscription, or the most recent one if you've rotated it. The digest is lowercase hex, prefixed with `sha256=`.
Sign over the **raw bytes you received**. Parsing the JSON and re-serialising it changes whitespace and key order, and the signature will not match.
```javascript Node.js theme={null}
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
export function verifyDelivery(rawBody, headers, secret) {
const timestamp = headers["x-webhook-timestamp"];
const signature = headers["x-signature"];
if (!timestamp || !signature) return false;
// Reject deliveries signed too long ago to be a live request.
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (!Number.isFinite(age) || age > TOLERANCE_SECONDS) return false;
const digest = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const expected = Buffer.from(`sha256=${digest}`);
const received = Buffer.from(signature);
return expected.length === received.length && timingSafeEqual(expected, received);
}
```
```python Python theme={null}
import hashlib
import hmac
import time
TOLERANCE_SECONDS = 300
def verify_delivery(raw_body: bytes, headers: dict, secret: str) -> bool:
timestamp = headers.get("x-webhook-timestamp")
signature = headers.get("x-signature")
if not timestamp or not signature:
return False
# Reject deliveries signed too long ago to be a live request.
if abs(int(time.time()) - int(timestamp)) > TOLERANCE_SECONDS:
return False
mac = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256)
expected = f"sha256={mac.hexdigest()}"
return hmac.compare_digest(expected, signature)
```
Compare signatures with a constant-time function, `timingSafeEqual` in Node.js or `hmac.compare_digest` in Python. A plain `==` leaks how much of the signature matched through its timing, which is enough to forge one given sufficient attempts.
The five-minute tolerance above is a suggestion, not something Spirii enforces. Pick a window that suits your infrastructure: too tight and a slow queue rejects legitimate deliveries, too loose and a captured request stays replayable for longer.
Because `event_id` and `X-Webhook-Id` are stable across retries, use either as an idempotency key. A retry after your handler succeeded but its response was lost is indistinguishable from a first delivery, so the same event will sometimes arrive twice.
## Respond to a delivery
Return any `2xx` status to acknowledge a delivery. Anything else, including a timeout, a connection error or a redirect, counts as a failure and is retried.
Acknowledge first and do the work afterwards. With a 10-second timeout, a handler that writes to a slow downstream system before responding will start failing under load, and those failures count against your subscription.
## Retries and failures
A failed delivery is retried up to **five attempts**, on a fixed schedule:
| Attempt | Sent |
| - | - |
| 1 | Immediately |
| 2 | 1 minute after the first attempt |
| 3 | 5 minutes later |
| 4 | 30 minutes later |
| 5 | 2 hours later |
After the fifth attempt the delivery is dead-lettered and that event is not sent again.
**Five consecutive failures disable the subscription.** `failure_count` counts consecutive failed attempts across all events and resets to `0` on any success, so a single event failing all five attempts is enough to move the subscription from `ACTIVE` to `FAILED`. Deliveries stop at that point, and events that occur while it's disabled are not queued for later.
To bring a disabled subscription back, fix the endpoint, then `PATCH /emsp/v1/webhooks/{webhook_id}` with `status: ACTIVE`. Confirm the endpoint works before you do: `failure_count` only clears on a successful delivery, so re-enabling with the count still at five means the next failure disables it again immediately. Send a [test delivery](#test-deliveries) first.
Pausing is different from failing. A subscription you set to `PAUSED` stays paused until you set it back, and is not counted as unhealthy.
## Test deliveries
`POST /emsp/v1/webhooks/{webhook_id}/test` sends a one-off signed payload to your endpoint and reports whether it was accepted.
The test leaves your subscription alone. It never changes `failure_count` or `status`, so a failing test costs you nothing, and a passing one does not clear a count that has already climbed. Its value is confirming the endpoint is healthy before you re-enable and spend the one delivery you have left.
Two things differ from a real delivery:
* **The body is not the standard envelope.** A test sends `type`, `webhook_id`, `event` and a `data` object holding a fixed message, with no `event_id`, `api_version`, `occurred_at` or `published_at`. `X-Webhook-Id` is `test_{webhook_id}` rather than an event id. A handler that validates the envelope strictly will reject a test and look broken when it isn't.
* **The timeout is 5 seconds**, against 10 for a real delivery. A handler responding close to that limit can fail a test it would have passed in production.
Signing is identical, so a test is a sound way to check your signature verification end to end.
## Monitor your subscription
`GET /emsp/v1/webhooks/{webhook_id}` returns five fields describing delivery health:
| Field | What it tells you |
| - | - |
| `failure_count` | Consecutive failures since the last success. At five, the subscription is disabled |
| `last_failure_at` | When the most recent failure happened |
| `last_success_at` | When a delivery last succeeded |
| `last_status_code` | The HTTP status your endpoint last returned, or null if the attempt never got one |
| `last_delivery_at` | When a delivery was last attempted, successful or not |
Alert on `failure_count` rather than on `status`. By the time `status` reads `FAILED` you've already lost the events that occurred during the outage, whereas a count climbing above one or two gives you a window to act.
A `last_status_code` of null alongside a rising `failure_count` points at a connection-level problem, such as an expired certificate or a DNS change, rather than an error your application returned.
## Related
Get a token and the scopes needed to manage subscriptions.
The Spirii APIs and their path prefixes.
The status codes the management endpoints return.
# Webhook events
Source: https://docs.spirii.com/api-reference/emsp/webhook-events
The event types you can subscribe to, what each one tells you, and which ones reach you.
Every event below can be subscribed to through the Webhooks endpoints. You only receive events for your own tenant.
This page is a snapshot, kept by hand so it can be read without calling the API. `GET /emsp/v1/webhooks/event_types` is the authoritative list, and returns the available versions for each type.
| Event | Reaches | What it tells you |
| - | - | - |
| `location.added` | Anyone whose network it falls in | A CPO has created a new site, and it falls within one of your networks. This is the first you'll hear of that location |
| `location.updated` | Anyone whose network it falls in | Something about a location changed. Re-read it to find out what |
| `location.removed` | Anyone whose network it fell in | A location has been withdrawn by its operator and should no longer be offered to drivers |
| `network.created` | The owner | A network was created |
| `network.updated` | The owner | A network's details changed. Carries the *names* of the fields that changed, not their values |
| `network.deleted` | The owner | A network was deleted, and how many token groups were unassigned as a result |
| `network.published` | The publisher | A base network was published and is now visible to other tenants |
| `network.unpublishing.started` | The publisher | A published network has begun winding down. It stays visible until the deadline in the event, so consumers have time to move |
| `network.unpublishing.completed` | The publisher | The wind-down finished and the network is no longer published |
| `network.consumer.attached` | The publisher | Another tenant has started consuming your published network |
| `network.consumer.detached` | The publisher | That tenant no longer consumes it |
## Payload shapes
The table above says what each event *means*. For the exact fields, fetch the schema:
```
GET /emsp/v1/webhooks/event_types/{type}
```
It returns every available `api_version` for that type and its payload JSON schema. Those schemas are served live — read them from the API rather than copying them into your code.
The envelope around `data` is identical for every event and is described on [Webhook delivery](/api-reference/emsp/webhook-delivery).
## Versioning
A subscription is pinned to one `api_version`, and that version's payload will not change shape underneath you. A field being removed or retyped means a new version, published alongside the old one, which you migrate to when you're ready.
## Related
Verify signatures, respond correctly, and keep a subscription healthy.
Get a token and the scopes needed to manage subscriptions.
The status codes the management endpoints return.
# Fetches a list of EVSEs.
Source: https://docs.spirii.com/api-reference/evses-v2/fetches-a-list-of-evses
/openapi/integration-api-v2/openapi.yaml get /v2/evses
# Fetches a single EVSE.
Source: https://docs.spirii.com/api-reference/evses-v2/fetches-a-single-evse
/openapi/integration-api-v2/openapi.yaml get /v2/evses/{uid}
# Requests an EVSE to start a transaction
Source: https://docs.spirii.com/api-reference/evses-v2/requests-an-evse-to-start-a-transaction
/openapi/integration-api-v2/openapi.yaml post /v2/evses/{uid}/connectors/{connectorId}/remote-start-transaction
# Requests an EVSE to stop a transaction
Source: https://docs.spirii.com/api-reference/evses-v2/requests-an-evse-to-stop-a-transaction
/openapi/integration-api-v2/openapi.yaml post /v2/evses/{uid}/connectors/{connectorId}/remote-stop-transaction
# Requests an EVSE to unlock a connector
Source: https://docs.spirii.com/api-reference/evses-v2/requests-an-evse-to-unlock-a-connector
/openapi/integration-api-v2/openapi.yaml post /v2/evses/{uid}/connectors/{connectorId}/unlock
# Updates a connector on an EVSE.
Source: https://docs.spirii.com/api-reference/evses-v2/updates-a-connector-on-an-evse
/openapi/integration-api-v2/openapi.yaml patch /v2/evses/{uid}/connectors/{connectorId}
# Updates the availability status of a connector.
Source: https://docs.spirii.com/api-reference/evses-v2/updates-the-availability-status-of-a-connector
/openapi/integration-api-v2/openapi.yaml post /v2/evses/{uid}/connectors/{connectorId}/change-availability
# Retrieve a EVSE's with their current status
Source: https://docs.spirii.com/api-reference/evses/retrieve-a-evses-with-their-current-status
/openapi/integrations-api/openapi.yml get /evses/{id}
# Retrieve a list of EVSE's with their current status
Source: https://docs.spirii.com/api-reference/evses/retrieve-a-list-of-evses-with-their-current-status
/openapi/integrations-api/openapi.yml get /evses
# Legacy API
Source: https://docs.spirii.com/api-reference/legacy-api/overview
The Spirii legacy API (v1) is deprecated. New integrations should use the Spirii API.
The Spirii legacy API is deprecated and will be removed on October 1st 2026. New integrations should use the [Spirii API V2](/api-reference/overview) instead. Existing integrations will be discontinued.
The legacy API (v1) covers Locations, EVSEs, and Transactions under the `https://api.spirii.com/` base URL.
# Creates a new location.
Source: https://docs.spirii.com/api-reference/locations-v2/creates-a-new-location
/openapi/integration-api-v2/openapi.yaml post /v2/locations
# Deletes an existing location. This operation cannot be undone.
Source: https://docs.spirii.com/api-reference/locations-v2/deletes-an-existing-location-this-operation-cannot-be-undone
/openapi/integration-api-v2/openapi.yaml delete /v2/locations/{id}
# Fetches a list of locations.
Source: https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations
/openapi/integration-api-v2/openapi.yaml get /v2/locations
# Fetches a single, existing location.
Source: https://docs.spirii.com/api-reference/locations-v2/fetches-a-single-existing-location
/openapi/integration-api-v2/openapi.yaml get /v2/locations/{id}
# Updates an existing location.
Source: https://docs.spirii.com/api-reference/locations-v2/updates-an-existing-location
/openapi/integration-api-v2/openapi.yaml patch /v2/locations/{id}
# Bulk availability check
Source: https://docs.spirii.com/api-reference/locations/bulk-availability-check
/openapi/emsp-location/openapi.yaml post /emsp/v1/locations/availability
# Get location detail
Source: https://docs.spirii.com/api-reference/locations/get-location-detail
/openapi/emsp-location/openapi.yaml get /emsp/v1/locations/{location_id}
# List available facility types
Source: https://docs.spirii.com/api-reference/locations/list-available-facility-types
/openapi/emsp-location/openapi.yaml get /emsp/v1/locations/facilities
# Map clustering
Source: https://docs.spirii.com/api-reference/locations/map-clustering
/openapi/emsp-location/openapi.yaml get /emsp/v1/locations/clusters
# Retrieve a list of locations
Source: https://docs.spirii.com/api-reference/locations/retrieve-a-list-of-locations
/openapi/integrations-api/openapi.yml get /locations
# Retrieve location by ID
Source: https://docs.spirii.com/api-reference/locations/retrieve-location-by-id
/openapi/integrations-api/openapi.yml get /locations/{id}
# Search and filter locations
Source: https://docs.spirii.com/api-reference/locations/search-and-filter-locations
/openapi/emsp-location/openapi.yaml get /emsp/v1/locations
# Update location data
Source: https://docs.spirii.com/api-reference/locations/update-location-data
/openapi/integrations-api/openapi.yml put /locations/{id}
# Create a BASE network
Source: https://docs.spirii.com/api-reference/networks/create-a-base-network
/openapi/emsp-network/openapi.yaml post /emsp/v1/networks/base
Creates a base network — the full collection of charging operators reachable through one of your roaming identities. Most organizations never call this: every roaming identity comes with its base network automatically, and day-to-day work happens in sub-networks.
# Create a TENANT sub-network
Source: https://docs.spirii.com/api-reference/networks/create-a-tenant-sub-network
/openapi/emsp-network/openapi.yaml post /emsp/v1/networks
Creates a named slice of a base network — for example "Fleet fast chargers" or "Premium partners" — which you can then assign to a group of charging tokens so those drivers see only these operators. The operators you pick must all be part of the chosen parent network. Supply an idempotency key to prevent duplicate creation on retry. If the parent network is in the middle of being withdrawn from publication, new slices of it cannot be created.
# Create an access rule
Source: https://docs.spirii.com/api-reference/networks/create-an-access-rule
/openapi/emsp-network/openapi.yaml post /emsp/v1/networks/{network_id}/rules
Adds an access rule to a network — either including a specific list of locations or excluding one. Rules can be scheduled: they start today unless you set a future start date, and can be given an end date after which they expire automatically. Important: adding the first rule to a network switches it from showing everything to showing only what the rules allow.
# Delete a TENANT sub-network
Source: https://docs.spirii.com/api-reference/networks/delete-a-tenant-sub-network
/openapi/emsp-network/openapi.yaml delete /emsp/v1/networks/{network_id}
Deletes a sub-network. Only sub-networks can be deleted — base networks are permanent. If the sub-network is still assigned to token groups, the deletion is blocked as a safety measure; set `force=true` to remove the assignments and delete anyway.
# Delete an access rule
Source: https://docs.spirii.com/api-reference/networks/delete-an-access-rule
/openapi/emsp-network/openapi.yaml delete /emsp/v1/networks/{network_id}/rules/{rule_id}
Removes an access rule from a network. The change applies immediately — what drivers can see and where they can charge may change the moment the rule is gone.
# Get effective network view (BASE networks with precedence applied)
Source: https://docs.spirii.com/api-reference/networks/get-effective-network-view-base-networks-with-precedence-applied
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks/effective-view
Returns which charging operators your organization can actually reach right now, and through which network. Merges all sources — your own base networks and any published ones you use — and applies the tie-break rule: where the same operator is reachable both ways, your own private network wins over a published one. Filter by country for a regional coverage overview, or to check why a particular operator is or isn't reachable. Sub-networks never appear here — they're slices used for assigning access to token groups, not sources of access themselves.
# Get network detail
Source: https://docs.spirii.com/api-reference/networks/get-network-detail
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks/{network_id}
Returns a single network by its ID — its operators, the countries it covers, how many locations and charge points it includes, which base network it belongs to (if it's a sub-network), and how many token groups are using it.
# List access rules for this network
Source: https://docs.spirii.com/api-reference/networks/list-access-rules-for-this-network
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks/{network_id}/rules
Lists the access rules on a network. A network with no rules shows everything; the moment you add the first rule, the network switches to showing only what the rules allow. Filter by validity to see only rules that are currently in effect, scheduled to start in the future, or already expired.
# List consumers of a Published BASE network (publisher-only)
Source: https://docs.spirii.com/api-reference/networks/list-consumers-of-a-published-base-network-publisher-only
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks/{network_id}/consumers
For publishers only: lists the organizations currently using one of your published base networks — those that have built slices of it for their own drivers. By default consumers appear as anonymous IDs; you only see full organization details when a consumer has chosen to share them. Useful for understanding who depends on your network before you withdraw it from publication.
# List networks
Source: https://docs.spirii.com/api-reference/networks/list-networks
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks
Lists your organization's networks. Use `network_type` to choose whether to list base networks (the full collections of charging operators your roaming identities can reach) or sub-networks (the named slices you've created from them). You can narrow the list further — for example to sub-networks of one particular parent, or to base networks that are published. Results come back a page at a time.
# List visible locations on this network
Source: https://docs.spirii.com/api-reference/networks/list-visible-locations-on-this-network
/openapi/emsp-network/openapi.yaml get /emsp/v1/networks/{network_id}/locations
Lists the charging locations actually visible on a sub-network, with access rules already applied — in other words, what a driver whose token group is assigned to this sub-network can see. Useful for verifying a slice before assigning it, or for troubleshooting why a driver can't see a particular charger.
# Set publish state on a BASE network
Source: https://docs.spirii.com/api-reference/networks/set-publish-state-on-a-base-network
/openapi/emsp-network/openapi.yaml patch /emsp/v1/networks/{network_id}/publish-state
Publishes one of your base networks to the whole platform — or begins withdrawing it. Publishing makes the network automatically visible to every organization on Spirii, so they can build slices of it for their own drivers. Publishing requires that Spirii has granted your organization the publishing capability. Withdrawing is deliberately gradual: the network enters a wind-down period (30 days by default) during which it stays visible so organizations using it have time to migrate. Requesting the state the network is already in returns an error rather than silently doing nothing.
# Update network settings
Source: https://docs.spirii.com/api-reference/networks/update-network-settings
/openapi/emsp-network/openapi.yaml patch /emsp/v1/networks/{network_id}
Changes a network's settings. What you can change depends on the network type: on a sub-network you can rename it, change its description, and adjust its operators; on a base network you can adjust the operators and whether its locations appear in anonymous charger searches — but not its name, which is derived from the roaming identity that owns it. When operators are removed from a base network, they're automatically removed from every slice of it too; newly added operators only flow into slices that have opted in to receive them.
# Overview
Source: https://docs.spirii.com/api-reference/overview
The four APIs that make up the Spirii Public API, their path prefixes, and where to start.
The Spirii Public API is a set of APIs for managing EV charging infrastructure and e-mobility services on the Spirii platform.
## Base URL
REST requests go to the production API:
```
https://api.spirii.com
```
Every REST endpoint in this reference ships with a request/response schema, parameter list, and an interactive **Try it** playground.
## The APIs
The reference covers four APIs. Three are REST: they share the host above, but each sits under its own path prefix, so check the prefix before you build a request. The fourth, the Energy Management API, is asynchronous: you address channels rather than paths, and Spirii provisions those addresses per actor during onboarding.
The core platform: locations, EVSEs, charge boxes, tariffs, charge keys, vouchers, customers, transactions, and charge records.
Example: `https://api.spirii.com/v2/transactions`
Spirii's mobility offering, addressed per tenant: tenant profiles, networks, locations, and webhooks.
Example: `https://api.spirii.com/emsp/v1/tenant/profile`
Reimbursement for home and workplace charging: expense reports and the rates they are calculated against.
Example: `https://api.spirii.com/reimbursement/v1/expense-reports`
[Programmatic Charger Control](/capabilities/energy-management/energy-management#programmatic-charger-control): external software, typically a third-party energy management system (EMS), reads real-time inputs and sends dynamic power limits to the chargers Spirii controls.
Example: the `control-request` channel, at an address provisioned per actor.
Each API is versioned independently. See [Versioning](/developers/versioning) for the current version of each and where it sits in the path.
Spirii does not currently offer a separate sandbox environment, so testing is done against production. We recommend connecting a test charger to run your integration tests safely.
## Where to next
Get an API key and authorize your first request.
The current version, version history, and deprecation policy.
A five-minute walkthrough to your first successful request.
The API rate limits and how to work with them.
# Add CDRs to Expense
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/add-cdrs-to-expense
/openapi/reimbursement/expenses/openapi.yaml post /v1/expenses/{expenseId}/charge-detail-records/add
Add Charge Detail Records to an expense.
# Approve Expense Report
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/approve-expense-report
/openapi/reimbursement/expenses/openapi.yaml post /v1/expense-reports/{reportId}/approve
Approves, stores, and sends emails for a expense report.
# Download Expense
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/download-expense
/openapi/reimbursement/expenses/openapi.yaml get /v1/expenses/{expenseId}/document
# Download Expense Report
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/download-expense-report
/openapi/reimbursement/expenses/openapi.yaml get /v1/expense-reports/{reportId}/document
# Get Expense
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/get-expense
/openapi/reimbursement/expenses/openapi.yaml get /v1/expenses/{expenseId}
# Get Expense Report
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/get-expense-report
/openapi/reimbursement/expenses/openapi.yaml get /v1/expense-reports/{reportId}
# List Expense Reports
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/list-expense-reports
/openapi/reimbursement/expenses/openapi.yaml get /v1/expense-reports
# List Unlinked CDRs
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/list-unlinked-cdrs
/openapi/reimbursement/expenses/openapi.yaml get /v1/expenses/{expenseId}/charge-detail-records/unlinked
Fetch a list of Charge Detail Records that are eligible for reimbursement, but not yet linked to an expense.
# Remove CDRs from Expense
Source: https://docs.spirii.com/api-reference/reimbursement-expenses/remove-cdrs-from-expense
/openapi/reimbursement/expenses/openapi.yaml post /v1/expenses/{expenseId}/charge-detail-records/remove
Remove Charge Detail Records from an expense.
# Create a new reimbursement rate
Source: https://docs.spirii.com/api-reference/reimbursement-rates/create-a-new-reimbursement-rate
/openapi/reimbursement/rates/openapi.yaml post /v1
# Delete a reimbursement rate and its attached documents
Source: https://docs.spirii.com/api-reference/reimbursement-rates/delete-a-reimbursement-rate-and-its-attached-documents
/openapi/reimbursement/rates/openapi.yaml delete /v1/{id}
# Get documents for a reimbursement rate
Source: https://docs.spirii.com/api-reference/reimbursement-rates/get-documents-for-a-reimbursement-rate
/openapi/reimbursement/rates/openapi.yaml get /v1/{id}/documents
Returns all documents attached to a reimbursement rate, each with a pre-signed download URL valid for 5 minutes.
# Get reimbursement rates for one or more locations
Source: https://docs.spirii.com/api-reference/reimbursement-rates/get-reimbursement-rates-for-one-or-more-locations
/openapi/reimbursement/rates/openapi.yaml get /v1
# Update an existing reimbursement rate
Source: https://docs.spirii.com/api-reference/reimbursement-rates/update-an-existing-reimbursement-rate
/openapi/reimbursement/rates/openapi.yaml patch /v1/{id}
# Upload document(s) for a reimbursement rate
Source: https://docs.spirii.com/api-reference/reimbursement-rates/upload-documents-for-a-reimbursement-rate
/openapi/reimbursement/rates/openapi.yaml post /v1/{id}/documents
Upload one or more files as supporting documents for a reimbursement rate.
# Get v2tariff publisherpublic key
Source: https://docs.spirii.com/api-reference/tariffpublisher-v2/get-v2tariff-publisherpublic-key
/openapi/integration-api-v2/openapi.yaml get /v2/tariff-publisher/public-key
# Fetches a single, existing tariff.
Source: https://docs.spirii.com/api-reference/tariffs-v2/fetches-a-single-existing-tariff
/openapi/integration-api-v2/openapi.yaml get /v2/tariffs/{id}
# Create a new Temporary EVSE Status
Source: https://docs.spirii.com/api-reference/temporary-evse-statuses-v2/create-a-new-temporary-evse-status
/openapi/integration-api-v2/openapi.yaml post /v2/temporary-evse-statuses
This API enables you, the Charge Point Operator (CPO)—the owners of chargers and EVSE, data—to temporarily override the **displayed** status of an EVSE (Electric Vehicle Supply Equipment) in e-mobility apps, without affecting its underlying technical or operational state.
We refer to this as a **Temporary EVSE Status**. It is designed for scenarios where an EVSE should not be used by customers for a limited period, such as during maintenance, commissioning, reservation, or temporary blocking, but where the EVSE itself remains technically operational.
**Key Distinction: Technical vs. Displayed (POI) Status**
- **Technical EVSE Status**:
The actual operational state of the EVSE, as reported by the charger using protocols like OCPP (e.g., Available, Charging, Faulted). This status reflects the real-time condition and capabilities of the hardware.
- **POI (Point of Interest) EVSE Status**:
The status shown to end-users in apps and roaming platforms. This can be overridden by this API to communicate temporary unavailability or special conditions, regardless of the technical status.
**This API only affects the POI status.** Communication with the charger and its technical state (OCPP status) remain unchanged.
#### Intended Use Cases
- **Maintenance**: Mark an EVSE as unavailable to users while it is being serviced, even if technically operational.
- **Commissioning**: Indicate that an EVSE is being set up or tested and not yet open for public use.
- **Blocking**: Temporarily prevent usage due to faults, safety concerns, or other operational reasons.
- **Reservation**: Show that an EVSE is reserved for a specific user or time period.
#### Status Mapping Across Protocols
When a Temporary EVSE Status is set, it is mapped to the corresponding display status in Spirii's app and major roaming platforms as follows:
| Temporary Status | Spirii Go App | Hubject (Roaming) | OCPI (Roaming) |
|--------------------|---------------|-------------------|-----------------|
| Maintenance | Unavailable | Out of Service | Inoperative |
| Commissioning | Coming Soon | Out of Service | Planned |
| Blocked | Blocked | Occupied | Blocked |
| Reserved | Reserved | Reserved | Reserved |
| Delay to eMSP Apps | Instant | Max 1 minute | Max 15 seconds |
**Note:** External eMSP (e-mobility service provider) apps may not reflect status changes immediately, as their update intervals can vary.
Once you create a Temporary EVSE Status, you receive a unique resource ID. This ID allows you to update (PATCH) the status (e.g., change the type or adjust the validFrom/validTo dates) or delete it to revert the EVSE back to its technical status. In other words, this is a full CRUD resource for managing temporary display statuses.
# Get a Temporary EVSE Status by ID
Source: https://docs.spirii.com/api-reference/temporary-evse-statuses-v2/get-a-temporary-evse-status-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/temporary-evse-statuses/{id}
# Get all Temporary EVSE Statuses
Source: https://docs.spirii.com/api-reference/temporary-evse-statuses-v2/get-all-temporary-evse-statuses
/openapi/integration-api-v2/openapi.yaml get /v2/temporary-evse-statuses
# Remove a Temporary EVSE Status
Source: https://docs.spirii.com/api-reference/temporary-evse-statuses-v2/remove-a-temporary-evse-status
/openapi/integration-api-v2/openapi.yaml delete /v2/temporary-evse-statuses/{id}
Removing a Temporary EVSE Status will make the eMSP Apps use the default charger statuses, like 'Available'.
# Update a Temporary EVSE Status
Source: https://docs.spirii.com/api-reference/temporary-evse-statuses-v2/update-a-temporary-evse-status
/openapi/integration-api-v2/openapi.yaml patch /v2/temporary-evse-statuses/{id}
# Get published-network priority order
Source: https://docs.spirii.com/api-reference/tenant/get-published-network-priority-order
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/published-network-priority-order
Returns your organization's preferred ranking of other providers' published charger networks. Spirii uses this ranking to break the tie when a charger can be reached through more than one network. If the list is empty, Spirii decides the order for you.
# Get tenant profile
Source: https://docs.spirii.com/api-reference/tenant/get-tenant-profile
/openapi/emsp-tenant/openapi.yaml get /emsp/v1/tenant/profile
Returns your organization's profile on Spirii — the top-level account that holds your roaming identities and your sharing preferences. You don't pass an ID Spirii recognizes you from your API credentials and always returns your own profile. It's a natural first call when you start integrating, both to confirm your access works and to see how your account is set up.
# Set published-network priority order
Source: https://docs.spirii.com/api-reference/tenant/set-published-network-priority-order
/openapi/emsp-tenant/openapi.yaml put /emsp/v1/tenant/published-network-priority-order
Sets your organization's preferred ranking of other providers' published charger networks, replacing the whole list in one go. Spirii uses this ranking only when a charger can be reached through more than one network. Each network you list has to be one your organization can actually access. Send an empty list to clear your preference and let Spirii choose the order.
# Update tenant profile
Source: https://docs.spirii.com/api-reference/tenant/update-tenant-profile
/openapi/emsp-tenant/openapi.yaml patch /emsp/v1/tenant/profile
Updates your organization's profile. Right now the only thing you can change here is the display name — everything else (your IDs, your roaming identities, and what you're allowed to publish) is either managed on its own endpoints or set by Spirii. Send just the display name you'd like to use.
# Activate group
Source: https://docs.spirii.com/api-reference/token-groups/activate-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/activate
Activates every PROVISIONED member token. The action is applied in the background to the tokens that are members when the call is made; tokens added later are not affected. Members whose status the action does not apply to are counted in `skipped`. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Add tokens to group
Source: https://docs.spirii.com/api-reference/token-groups/add-tokens-to-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/tokens
Adds tokens to the group and returns the updated group. A token can be a member of any number of groups, so adding it here does not remove it from other groups. The members of a group cannot be listed yet. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Assign network to group
Source: https://docs.spirii.com/api-reference/token-groups/assign-network-to-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/networks
Assigns a network to the group, so member tokens can charge on the CPOs it contains. Every network a token reaches, across all of its groups, must be built on the same BASE network. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Associate a location to a token group
Source: https://docs.spirii.com/api-reference/token-groups/associate-a-location-to-a-token-group
/openapi/integration-api-v2/openapi.yaml post /v2/token-groups/{id}/locations/{locationId}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Associate a token to a token group
Source: https://docs.spirii.com/api-reference/token-groups/associate-a-token-to-a-token-group
/openapi/integration-api-v2/openapi.yaml post /v2/token-groups/{id}/tokens/{tokenId}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Create a new token group
Source: https://docs.spirii.com/api-reference/token-groups/create-a-new-token-group
/openapi/integration-api-v2/openapi.yaml post /v2/token-groups
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Create token group
Source: https://docs.spirii.com/api-reference/token-groups/create-token-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups
Creates an empty token group.
Requires the `emsp:tokens:write` scope.
# Delete a token group
Source: https://docs.spirii.com/api-reference/token-groups/delete-a-token-group
/openapi/integration-api-v2/openapi.yaml delete /v2/token-groups/{id}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Disable a token group
Source: https://docs.spirii.com/api-reference/token-groups/disable-a-token-group
/openapi/integration-api-v2/openapi.yaml post /v2/token-groups/{id}/disable
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Disassociate a location from a token group
Source: https://docs.spirii.com/api-reference/token-groups/disassociate-a-location-from-a-token-group
/openapi/integration-api-v2/openapi.yaml delete /v2/token-groups/{id}/locations/{locationId}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Disassociate a token from a token group
Source: https://docs.spirii.com/api-reference/token-groups/disassociate-a-token-from-a-token-group
/openapi/integration-api-v2/openapi.yaml delete /v2/token-groups/{id}/tokens/{tokenId}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Enable a token group
Source: https://docs.spirii.com/api-reference/token-groups/enable-a-token-group
/openapi/integration-api-v2/openapi.yaml post /v2/token-groups/{id}/enable
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Get a list of locations associated to a token group by ID
Source: https://docs.spirii.com/api-reference/token-groups/get-a-list-of-locations-associated-to-a-token-group-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/token-groups/{id}/locations
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Get a list of token groups
Source: https://docs.spirii.com/api-reference/token-groups/get-a-list-of-token-groups
/openapi/integration-api-v2/openapi.yaml get /v2/token-groups
This endpoint allows you to get a paginated list of token groups. It is possible to set query parameters to filter the results.
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Get a list of tokens associated to a token group by ID
Source: https://docs.spirii.com/api-reference/token-groups/get-a-list-of-tokens-associated-to-a-token-group-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/token-groups/{id}/tokens
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Get a token group by ID
Source: https://docs.spirii.com/api-reference/token-groups/get-a-token-group-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/token-groups/{id}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Get token group detail
Source: https://docs.spirii.com/api-reference/token-groups/get-token-group-detail
/openapi/emsp-token/openapi.yaml get /emsp/v1/token-groups/{groupId}
Requires the `emsp:tokens:read` scope.
# List network assignments
Source: https://docs.spirii.com/api-reference/token-groups/list-network-assignments
/openapi/emsp-token/openapi.yaml get /emsp/v1/token-groups/{groupId}/networks
Lists the networks assigned to the group. Member tokens can charge on the CPOs these networks contain. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:read` scope.
# List token groups
Source: https://docs.spirii.com/api-reference/token-groups/list-token-groups
/openapi/emsp-token/openapi.yaml get /emsp/v1/token-groups
Lists the token groups in your tenant, one page at a time.
Requires the `emsp:tokens:read` scope.
# Reactivate group
Source: https://docs.spirii.com/api-reference/token-groups/reactivate-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/reactivate
Reactivates every SUSPENDED member token. The action is applied in the background to the tokens that are members when the call is made; tokens added later are not affected. Members whose status the action does not apply to are counted in `skipped`. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Remove network assignment
Source: https://docs.spirii.com/api-reference/token-groups/remove-network-assignment
/openapi/emsp-token/openapi.yaml delete /emsp/v1/token-groups/{groupId}/networks/{networkId}
Removes a network from the group. Member tokens stop reaching its CPOs once the change has propagated. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Remove token from group
Source: https://docs.spirii.com/api-reference/token-groups/remove-token-from-group
/openapi/emsp-token/openapi.yaml delete /emsp/v1/token-groups/{groupId}/tokens/{tokenId}
Removes one token from the group. The token itself and its other group memberships are unchanged. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Revoke group
Source: https://docs.spirii.com/api-reference/token-groups/revoke-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/revoke
Revokes every member token that is not already REVOKED. Revocation is permanent. The action is applied in the background to the tokens that are members when the call is made; tokens added later are not affected. Members whose status the action does not apply to are counted in `skipped`. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Suspend group
Source: https://docs.spirii.com/api-reference/token-groups/suspend-group
/openapi/emsp-token/openapi.yaml post /emsp/v1/token-groups/{groupId}/suspend
Suspends every ACTIVE member token. The action is applied in the background to the tokens that are members when the call is made; tokens added later are not affected. Members whose status the action does not apply to are counted in `skipped`. Not available yet: a request that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Update a token group
Source: https://docs.spirii.com/api-reference/token-groups/update-a-token-group
/openapi/integration-api-v2/openapi.yaml patch /v2/token-groups/{id}
A token group is an access management mechanism where only tokens inside a group can authorize charging at specified locations.
The group **always** grants access to the location. This means the location's public setting and opening hours are overruled by a token inside the group.
# Update token group
Source: https://docs.spirii.com/api-reference/token-groups/update-token-group
/openapi/emsp-token/openapi.yaml patch /emsp/v1/token-groups/{groupId}
Partially updates a group: fields left out are unchanged, and `description`, `emsp_identity_id`, `external_id` and `metadata` can be cleared with null. Member tokens and networks are managed through their own operations, and any other field in the body is ignored.
Requires the `emsp:tokens:write` scope.
# Activate token
Source: https://docs.spirii.com/api-reference/tokens/activate-token
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens/{tokenId}/activate
Moves a PROVISIONED token to ACTIVE, so it can authorize charging and is distributed to whitelist-capable CPO networks. Distribution runs in the background, and `whitelist_distributed` says whether it has completed, so it can be false in this response and turn true later. Use reactivate for a SUSPENDED token.
Requires the `emsp:tokens:write` scope.
# Bulk provision tokens
Source: https://docs.spirii.com/api-reference/tokens/bulk-provision-tokens
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens/bulk
Accepts up to 1000 tokens for provisioning in the background. The batch is validated as a whole before it is accepted: one invalid item rejects the batch with 422, and each entry in `errors` names the item by index (`body.tokens[].`). uid uniqueness and metadata validation run per item during processing rather than on this call. This operation does not use the Idempotency-Key header; instead each item carries its own `idempotency_key`. Bulk import is not available yet: a batch that passes validation is answered 501 (`NOT_IMPLEMENTED`), and retrying will not help.
Requires the `emsp:tokens:write` scope.
# Create a new token
Source: https://docs.spirii.com/api-reference/tokens/create-a-new-token
/openapi/integration-api-v2/openapi.yaml post /v2/tokens
This endpoint allows you to create new token(s).
In EV charging systems, tokens (also known as ID tags or charge keys) are unique identifiers that authenticate users to initiate a charging session. Spirii differentiates between three different types of tokens:
- RFIDs represent a physical identifier with a MiFare chip that can be read by chargers.
- Virtual tokens represent a digital identifier for authentication through the Spirii app (or a branded app)
- Vehicle tokens (also known as “Autocharge”) represent the vehicle's MAC address or VIN code that when registered in Spirii’s platform. They allow a charger to recognize a vehicle and authorize charging when a vehicle is plugged in.
# Delete a token
Source: https://docs.spirii.com/api-reference/tokens/delete-a-token
/openapi/integration-api-v2/openapi.yaml delete /v2/tokens/{id}
This endpoint allows you to delete a token. Deleting a token sets the token to isActive = false.
**Please note that once a token is deleted, it is not possible to create a new one with the same UID**
# Disable a token
Source: https://docs.spirii.com/api-reference/tokens/disable-a-token
/openapi/integration-api-v2/openapi.yaml post /v2/tokens/{id}/disable
This endpoint allows you to disable a token.
# Enable a token
Source: https://docs.spirii.com/api-reference/tokens/enable-a-token
/openapi/integration-api-v2/openapi.yaml post /v2/tokens/{id}/enable
This endpoint allows you to enable a token.
# Get a list of tokens
Source: https://docs.spirii.com/api-reference/tokens/get-a-list-of-tokens
/openapi/integration-api-v2/openapi.yaml get /v2/tokens
This endpoint allows you to get a paginated list of tokens. It is possible to set query parameters to filter the results.
In EV charging systems, tokens (also known as ID tags or charge keys) are unique identifiers that authenticate users to initiate a charging session. Spirii differentiates between three different types of tokens:
- RFIDs represent a physical identifier with a MiFare chip that can be read by chargers.
- Virtual tokens represent a digital identifier for authentication through the Spirii app (or a branded app)
- Vehicle tokens (also known as “Autocharge”) represent the vehicle's MAC address or VIN code that when registered in Spirii’s platform. They allow a charger to recognize a vehicle and authorize charging when a vehicle is plugged in.
# Get a token by ID
Source: https://docs.spirii.com/api-reference/tokens/get-a-token-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/tokens/{id}
This endpoint allows you to get a token by its ID.
In EV charging systems, tokens (also known as ID tags or charge keys) are unique identifiers that authenticate users to initiate a charging session. Spirii differentiates between three different types of tokens:
- RFIDs represent a physical identifier with a MiFare chip that can be read by chargers.
- Virtual tokens represent a digital identifier for authentication through the Spirii app (or a branded app)
- Vehicle tokens (also known as “Autocharge”) represent the vehicle's MAC address or VIN code that when registered in Spirii’s platform. They allow a charger to recognize a vehicle and authorize charging when a vehicle is plugged in.
# Get token detail
Source: https://docs.spirii.com/api-reference/tokens/get-token-detail
/openapi/emsp-token/openapi.yaml get /emsp/v1/tokens/{tokenId}
Requires the `emsp:tokens:read` scope.
# Get token history
Source: https://docs.spirii.com/api-reference/tokens/get-token-history
/openapi/emsp-token/openapi.yaml get /emsp/v1/tokens/{tokenId}/history
Lists the lifecycle events of a token, newest first unless `sort_direction=asc`, optionally narrowed to some event types.
Requires the `emsp:tokens:read` scope.
# List tokens
Source: https://docs.spirii.com/api-reference/tokens/list-tokens
/openapi/emsp-token/openapi.yaml get /emsp/v1/tokens
Lists the tokens in your tenant, one page at a time.
Requires the `emsp:tokens:read` scope.
# Provision a new token
Source: https://docs.spirii.com/api-reference/tokens/provision-a-new-token
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens
Registers a token in your tenant. The token starts in PROVISIONED, or in ACTIVE when `auto_activate` is true. `uid` must be unique across every tenant on the platform, and `metadata` is validated against the tenant TOKEN metadata schema. A tenant without a TOKEN metadata schema cannot store metadata: any non-empty map is a 422.
Requires the `emsp:tokens:write` scope.
# Reactivate token
Source: https://docs.spirii.com/api-reference/tokens/reactivate-token
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens/{tokenId}/reactivate
Moves a SUSPENDED token back to ACTIVE.
Requires the `emsp:tokens:write` scope.
# Revoke token
Source: https://docs.spirii.com/api-reference/tokens/revoke-token
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens/{tokenId}/revoke
Permanently invalidates a PROVISIONED, ACTIVE or SUSPENDED token and sets `invalidated_at`. REVOKED and EXPIRED are terminal: no action moves a token out of either, and revoking one is a 409. An optional `reason` is recorded on the history event.
Requires the `emsp:tokens:write` scope.
# Suspend token
Source: https://docs.spirii.com/api-reference/tokens/suspend-token
/openapi/emsp-token/openapi.yaml post /emsp/v1/tokens/{tokenId}/suspend
Moves an ACTIVE token to SUSPENDED, so it stops authorizing charging until it is reactivated. An optional `reason` is recorded on the history event.
Requires the `emsp:tokens:write` scope.
# Update a token
Source: https://docs.spirii.com/api-reference/tokens/update-a-token
/openapi/integration-api-v2/openapi.yaml patch /v2/tokens/{id}
This endpoint allows you to update a token.
In EV charging systems, tokens (also known as ID tags or charge keys) are unique identifiers that authenticate users to initiate a charging session. Spirii differentiates between three different types of tokens:
- RFIDs represent a physical identifier with a MiFare chip that can be read by chargers.
- Virtual tokens represent a digital identifier for authentication through the Spirii app (or a branded app)
- Vehicle tokens (also known as “Autocharge”) represent the vehicle's MAC address or VIN code that when registered in Spirii’s platform. They allow a charger to recognize a vehicle and authorize charging when a vehicle is plugged in.
# Update token attributes
Source: https://docs.spirii.com/api-reference/tokens/update-token-attributes
/openapi/emsp-token/openapi.yaml patch /emsp/v1/tokens/{tokenId}
Partially updates a token: fields left out are unchanged. Only `visual_number`, `issuer`, `language`, `valid_until`, `whitelist` and `metadata` can be changed here. `contract_id` never changes after create, so sending it is a 422; any other unknown field is ignored. Send null to clear `visual_number`, `language`, `valid_until` or `metadata`. `metadata` replaces the stored map and is validated against the tenant TOKEN metadata schema. A tenant without a TOKEN metadata schema cannot store metadata: any non-empty map is a 422. Status changes go through the lifecycle actions.
Requires the `emsp:tokens:write` scope.
# Get a list of transactions
Source: https://docs.spirii.com/api-reference/transactions-v2/get-a-list-of-transactions
/openapi/integration-api-v2/openapi.yaml get /v2/transactions
Returns a list of Transactions. It is possible to set query parameters to filter the results.
# Get a transaction by ID
Source: https://docs.spirii.com/api-reference/transactions-v2/get-a-transaction-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/transactions/{id}
Returns a single Transaction from a given transactionId.
# Retrieve a list of transactions
Source: https://docs.spirii.com/api-reference/transactions/retrieve-a-list-of-transactions
/openapi/integrations-api/openapi.yml get /transactions
# Retrieve complete transaction data by ID
Source: https://docs.spirii.com/api-reference/transactions/retrieve-complete-transaction-data-by-id
/openapi/integrations-api/openapi.yml get /transactions/{id}
# Retrieve a list of voucher groups
Source: https://docs.spirii.com/api-reference/voucher-groups/retrieve-a-list-of-voucher-groups
/openapi/integrations-api/openapi.yml get /voucher-groups
# Retrieve all information about a specific Voucher Group
Source: https://docs.spirii.com/api-reference/voucher-groups/retrieve-all-information-about-a-specific-voucher-group
/openapi/integrations-api/openapi.yml get /voucher-groups/{id}
# Update a voucher group
Source: https://docs.spirii.com/api-reference/voucher-groups/update-a-voucher-group
/openapi/integrations-api/openapi.yml put /voucher-groups/{id}
# Associate location to voucher group
Source: https://docs.spirii.com/api-reference/vouchergroups/associate-location-to-voucher-group
/openapi/integration-api-v2/openapi.yaml post /v2/voucher-groups/{id}/locations/{locationId}
Allows you to associate location to a specific voucher group
A Voucher Group unites several Vouchers
# Create a new voucher group
Source: https://docs.spirii.com/api-reference/vouchergroups/create-a-new-voucher-group
/openapi/integration-api-v2/openapi.yaml post /v2/voucher-groups
This endpoint allows you to create a voucher group
A Voucher Group unites several Vouchers
# Delete a voucher group by ID
Source: https://docs.spirii.com/api-reference/vouchergroups/delete-a-voucher-group-by-id
/openapi/integration-api-v2/openapi.yaml delete /v2/voucher-groups/{id}
This endpoint allows you to delete a voucher by its ID.
# Disassociate locations from voucher group
Source: https://docs.spirii.com/api-reference/vouchergroups/disassociate-locations-from-voucher-group
/openapi/integration-api-v2/openapi.yaml delete /v2/voucher-groups/{id}/locations/{locationId}
Allows you to disassociate locations from a specific voucher group
A Voucher Group unites several Vouchers
# Get a list of voucher groups
Source: https://docs.spirii.com/api-reference/vouchergroups/get-a-list-of-voucher-groups
/openapi/integration-api-v2/openapi.yaml get /v2/voucher-groups
This endpoint allows you to get a paginated list of voucher groups. It is possible to set query parameters to filter the results.
A Voucher Group unites several Vouchers
# Get a paginated list of vouchers belonging to a voucher group
Source: https://docs.spirii.com/api-reference/vouchergroups/get-a-paginated-list-of-vouchers-belonging-to-a-voucher-group
/openapi/integration-api-v2/openapi.yaml get /v2/voucher-groups/{id}/vouchers
This endpoint allows you to get a paginated list of vouchers belonging to a certain voucher group. It is possible to set query parameters to filter and paginate the results.
A Voucher Group unites several Vouchers
# Get a voucher group by ID
Source: https://docs.spirii.com/api-reference/vouchergroups/get-a-voucher-group-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/voucher-groups/{id}
A Voucher Group unites several Vouchers
# Get voucher group's locations by ID
Source: https://docs.spirii.com/api-reference/vouchergroups/get-voucher-groups-locations-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/voucher-groups/{id}/locations
This endpoint allows you to fetch locations associated with a voucher group.
A Voucher Group unites several Vouchers
# Update an existing voucher group
Source: https://docs.spirii.com/api-reference/vouchergroups/update-an-existing-voucher-group
/openapi/integration-api-v2/openapi.yaml patch /v2/voucher-groups/{id}
This endpoint allows you to update an existing voucher group.
A Voucher Group unites several Vouchers
# Associate a token to a voucher
Source: https://docs.spirii.com/api-reference/vouchers/associate-a-token-to-a-voucher
/openapi/integration-api-v2/openapi.yaml post /v2/vouchers/{id}/tokens/{tokenId}
This endpoint allows you to associate a token to a voucher.
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Create a new voucher
Source: https://docs.spirii.com/api-reference/vouchers/create-a-new-voucher
/openapi/integration-api-v2/openapi.yaml post /v2/vouchers
This endpoint allows you to create a voucher(s).
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Delete a voucher by ID
Source: https://docs.spirii.com/api-reference/vouchers/delete-a-voucher-by-id
/openapi/integration-api-v2/openapi.yaml delete /v2/vouchers/{id}
This endpoint allows you to delete a voucher by its ID.
# Disable a voucher (sets it as expired)
Source: https://docs.spirii.com/api-reference/vouchers/disable-a-voucher-sets-it-as-expired
/openapi/integrations-api/openapi.yml delete /vouchers/{id}
# Disassociate a token from a voucher
Source: https://docs.spirii.com/api-reference/vouchers/disassociate-a-token-from-a-voucher
/openapi/integration-api-v2/openapi.yaml delete /v2/vouchers/{id}/tokens/{tokenId}
This endpoint allows you to disassociate a token from a voucher.
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Get a list of vouchers
Source: https://docs.spirii.com/api-reference/vouchers/get-a-list-of-vouchers
/openapi/integration-api-v2/openapi.yaml get /v2/vouchers
This endpoint allows you to get a paginated list of vouchers. It is possible to set query parameters to filter the results.
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Get a voucher by ID
Source: https://docs.spirii.com/api-reference/vouchers/get-a-voucher-by-id
/openapi/integration-api-v2/openapi.yaml get /v2/vouchers/{id}
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Get tokens associated with a voucher by voucher ID
Source: https://docs.spirii.com/api-reference/vouchers/get-tokens-associated-with-a-voucher-by-voucher-id
/openapi/integration-api-v2/openapi.yaml get /v2/vouchers/{id}/tokens
List of token IDs associated with the voucher.
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Retrieve a list of vouchers
Source: https://docs.spirii.com/api-reference/vouchers/retrieve-a-list-of-vouchers
/openapi/integrations-api/openapi.yml get /vouchers
# Retrieve a specific voucher
Source: https://docs.spirii.com/api-reference/vouchers/retrieve-a-specific-voucher
/openapi/integrations-api/openapi.yml get /vouchers/{id}
# Update a voucher
Source: https://docs.spirii.com/api-reference/vouchers/update-a-voucher
/openapi/integrations-api/openapi.yml put /vouchers/{id}
# Update an existing voucher
Source: https://docs.spirii.com/api-reference/vouchers/update-an-existing-voucher
/openapi/integration-api-v2/openapi.yaml patch /v2/vouchers/{id}
This endpoint allows you to update an existing voucher.
A Voucher belongs to a Voucher Group and is uniquely identified by a code.
It can be linked to multiple tokens (idtags) and appUsers.
When a driver starts a session at a location, the system checks:
If the driver’s token is linked to a voucher, or
If the driver’s appUser (linked to that token) is linked to a voucher.
If either is true and the voucher’s group is associated with the location, the voucher is applied — potentially affecting pricing or granting access.
# Delete a webhook subscription
Source: https://docs.spirii.com/api-reference/webhooks/delete-a-webhook-subscription
/openapi/emsp-webhook/openapi.yaml delete /emsp/v1/webhooks/{webhook_id}
Deregisters a webhook subscription. Future deliveries stop immediately.
# Get a webhook subscription
Source: https://docs.spirii.com/api-reference/webhooks/get-a-webhook-subscription
/openapi/emsp-webhook/openapi.yaml get /emsp/v1/webhooks/{webhook_id}
Returns a single webhook subscription. The secret and custom-header values are never returned.
# Get an event type
Source: https://docs.spirii.com/api-reference/webhooks/get-an-event-type
/openapi/emsp-webhook/openapi.yaml get /emsp/v1/webhooks/event_types/{type}
Returns each available api_version of an event type and its payload JSON schema.
# List subscribable event types
Source: https://docs.spirii.com/api-reference/webhooks/list-subscribable-event-types
/openapi/emsp-webhook/openapi.yaml get /emsp/v1/webhooks/event_types
Returns the controlled list of event types you can subscribe a webhook to.
# List webhook subscriptions
Source: https://docs.spirii.com/api-reference/webhooks/list-webhook-subscriptions
/openapi/emsp-webhook/openapi.yaml get /emsp/v1/webhooks
Lists your webhook subscriptions. Supports cursor pagination and filtering by event type. Secrets and custom-header values are never returned.
# Register a webhook
Source: https://docs.spirii.com/api-reference/webhooks/register-a-webhook
/openapi/emsp-webhook/openapi.yaml post /emsp/v1/webhooks
Registers a webhook subscription for an event type. Spirii generates the signing secret and returns it once in this response — store it securely, it is never shown again.
# Send a test delivery
Source: https://docs.spirii.com/api-reference/webhooks/send-a-test-delivery
/openapi/emsp-webhook/openapi.yaml post /emsp/v1/webhooks/{webhook_id}/test
Sends a one-off signed test payload to the subscription endpoint and reports the result. It does not affect the failure count or the subscription status.
# Update a webhook subscription
Source: https://docs.spirii.com/api-reference/webhooks/update-a-webhook-subscription
/openapi/emsp-webhook/openapi.yaml patch /emsp/v1/webhooks/{webhook_id}
Updates a webhook subscription — pause/resume it, change the URL or custom headers, or rotate the signing secret. When you request rotation the new secret is returned once in this response.
# Asset Management (Master Data)
Source: https://docs.spirii.com/api-reference/websockets/asset-management-master-data
Pushed when an asset (chargebox or circuit) registered with the actor is
subscribed, unsubscribed, or updated. Update messages only include the
fields that changed.
# Connector Status Update
Source: https://docs.spirii.com/api-reference/websockets/connector-status-update
Pushed whenever the status of a connector registered with the actor
changes.
# Control Request
Source: https://docs.spirii.com/api-reference/websockets/control-request
Single endpoint accepting all control command types. Since processing is
asynchronous, the HTTP response only reflects whether the request was
accepted for processing (authenticated, well-formed) — the actual outcome
of applying the request is delivered later as a `controlResponse` message
correlated by `request_id`.
### Rate limiting
Limited to 1 request every 5 seconds, tracked independently for each connector and action — i.e. `SET_EVSE_INPUT_LIMIT`
is tracked separately from `CLEAR_EVSE_INPUT_LIMIT` and individually per asset. Exceeding it produces a `controlResponse` with
`result: TOO_MANY_REQUESTS`.
# Control Response
Source: https://docs.spirii.com/api-reference/websockets/control-response
Delivers the outcome of a previously submitted control request. One message
per `request_id`.
# Power Measurements
Source: https://docs.spirii.com/api-reference/websockets/power-measurements
Near-real-time active power readings for chargeboxes and circuits
registered with the actor.
# Charge key authentication
Source: https://docs.spirii.com/capabilities/access/charge-key-authentication
How you issue charge keys to your drivers and control where they can charge.
Charge keys are how your drivers authenticate to charge, and issuing them is how you grant your fleet access: on your own depot and workplace chargers, and out on roaming networks across the ecosystem. This is where you create charge keys, decide how they're billed, and control where they work.
## Overview
A [charge key](/components/access/charge-keys) identifies a driver or vehicle at a charger. When a session starts, the platform recognises the charge key, authorises the charge, and knows how to bill it, with no need for the driver to enter payment details each time.
As a fleet or mobility operator, you issue charge keys to your drivers and they reach two kinds of charger:
The depots, workplaces, and sites you operate.
Other operators' chargers across the ecosystem, when a charge key is enabled for roaming.
The [Charge keys component](/components/access/charge-keys) covers what a charge key is and how billing attaches to it; this page is how you issue and manage them.
In the API, charge keys are called **tokens** and charge key groups are called **token groups** — for example `POST /v2/tokens`. The object is the same; only the name differs.
## Charge key types
You choose a type when you issue a charge key, and it decides how the driver authenticates.
| Type | How the driver authenticates |
| - | - |
| RFID | Taps a physical card or fob at the charger |
| Virtual | Starts the session from Spirii Go or your branded app |
| Vehicle (Autocharge) | Plugs in; the charger recognises the vehicle by its VIN or MAC address |
Some chargers also support **Plug & Charge**, a certificate-based method where the vehicle authenticates itself on plug-in. It's enabled on the charger rather than issued as a charge key type.
Autocharge only works on chargers managed by Spirii's platform, not over roaming. A driver relying on Autocharge won't be recognised on other operators' chargers.
## Issuing charge keys
You create and manage charge keys in Spirii Connect under **Charge Keys**.
Choose the **billing customer**: the account that owns the charge key and is invoiced for its sessions. For a fleet, this is typically the fleet itself, so all charging lands on one invoice.
Pick RFID, Virtual, or Vehicle, then supply the identifier: an RFID chip's UID, a vehicle's VIN or MAC address, or an autogenerated ID for a virtual key.
Give the charge key a label that's unique in Connect. An RFID reference like `DK.SPI.0001234` works, or a fleet vehicle ID like `EVBUS.0007`. Labels are how you recognise a charge key later across reports and groups.
Set the charge key active so it can charge, and enable roaming if your drivers need to charge on other networks. Give it a validity period with a start and an optional end date.
### Bulk uploading
Onboarding a whole fleet at once, you can bulk-upload charge keys from a CSV of UIDs and labels, up to 100 per upload, rather than creating them one by one.
## Billing and ownership
Every charge key has a billing customer who's invoiced monthly for all its sessions, the model that lets a fleet consolidate every driver's charging into a single invoice. Alternatively, a driver can link their own payment card to a physical key in the app, so their sessions are billed to them directly.
When you hand a physical key to a driver, they finish the link themselves: they add the key in Spirii Go or your branded app, attach a payment method (or rely on the company billing you've set up), and activate it. From then on they can charge by tapping the key, without opening the app.
## Where a charge key works
### On your own sites
At any of your public locations, an active charge key works straight away. To reserve a depot or workplace for your fleet alone, put its charge keys in a **charge key group** and bind that group to the location: only charge keys in the group can charge there, and they can do so even when the location isn't public. How that interacts with a location's other settings is covered in [Location access](/capabilities/access/location-access).
### On roaming networks
Enable a charge key for roaming and it authorises on other operators' chargers across the networks Spirii connects to; that's the on-the-route half of a fleet's charging. See [Roaming connection](/capabilities/roaming/roaming-connection) for how roaming access is established.
A charge key only works on roaming networks when it's active, enabled for roaming, and labelled in the recommended `DK.SPI.C{customerPrefix}` format. An incorrectly labelled charge key is a common reason a driver can't charge on another network. See [Roaming connection](/capabilities/roaming/roaming-connection) for the details.
## Dependencies & limitations
* **A charge key needs a billing customer and activation.** It can't charge until it's active and owned by a billing customer.
* **Labels and IDs are unique.** Each charge key's UID and label must be unique in Connect.
* **Bulk upload is capped.** A CSV upload creates up to 100 charge keys at a time.
* **Requiring a charge key is a charger setting.** Whether a charger demands authentication or lets charging start on plug-in is set on the charge box, not the charge key.
* **Charge key groups override location settings.** A charge key group always grants its members access, ahead of a location's public setting and opening hours. See [Location access](/capabilities/access/location-access).
## Related
What a charge key is, its types, and how billing attaches to it.
How a charge key reaches chargers on other networks.
Attach a voucher to a charge key for access and a set rate at specific locations.
Create and manage charge keys programmatically.
How charge keys, groups, and vouchers decide who can charge at a location.
# Location access
Source: https://docs.spirii.com/capabilities/access/location-access
How visibility and authorisation combine to control who can find a location and who can charge there.
Location access is how you control two things at a site: who can see it, and who can charge there. You set both through a location's own settings and the charge keys and vouchers that grant access to it.
## Overview
Access has two aspects, and every mechanism below controls one or both:
Whether a driver can find the location in an app or map.
Whether a driver can actually start a charging session there.
A location's own settings set the baseline, and charge keys and vouchers layer on top to open access to specific drivers. Each mechanism has a home of its own; this page is how they fit together.
| Mechanism | Controls | Set in |
| - | - | - |
| Publicly available | Visibility and authorisation | [Location configuration](/capabilities/connection/location-configuration) |
| Hidden from charging apps | Visibility | [Location configuration](/capabilities/connection/location-configuration) |
| Enabled for roaming | Visibility and authorisation | [Location configuration](/capabilities/connection/location-configuration) |
| Opening hours | Visibility and authorisation | [Location configuration](/capabilities/connection/location-configuration#opening-hours) |
| Charge keys | Authorisation | [Charge keys](/components/access/charge-keys) |
| Charge key groups | Authorisation | [Charge keys](/components/access/charge-keys) |
| Vouchers | Visibility and authorisation | [Vouchers](/components/access/vouchers) |
## Who can see a location
Two publishing settings decide visibility, and they work independently:
* **Publicly available** lists the location in Spirii Go and the maps where Spirii shares location data, so any driver can find it.
* **Hidden from charging apps** removes that listing without changing who can charge — a driver who already knows the site is there, and carries a valid charge key, can still use it.
Combined, they give three practical states:
| Publicly available | Hidden from apps | Result |
| - | - | - |
| | | Listed in the apps and open to any registered charge key |
| | | Not listed, but any registered charge key can charge on arrival |
| | | Not listed, and only vouchers or bound charge key groups can charge |
**Enabled for roaming** extends visibility further, publishing the location to drivers on other networks through Spirii's roaming partners. See [Roaming connection](/capabilities/roaming/roaming-connection) for how that works. These settings are configured on the location itself — see [Location configuration](/capabilities/connection/location-configuration).
## Who can charge
Whether a driver can start a session comes down to the charge key they present and the access tied to the location.
A [charge key](/components/access/charge-keys) authorises charging at any public location in the Spirii network, and on roaming networks too when the location has roaming enabled. This is the default path for a public site: any registered, active charge key works.
A **charge key group** restricts a set of locations to the charge keys inside it. Only those charge keys can authorise there, and they can do so even when the location isn't public — a charge key group always grants its members access. It's how you make a depot exclusive to your own fleet's keys.
A [voucher](/components/access/vouchers) grants a driver both access and a specific rate at a defined set of locations. A driver enters the voucher code in the app, or you link it to a charge key, and it opens access even where the location is private. See [Voucher access](/capabilities/access/voucher-access) for the full mechanism.
Chargers can also require authentication or allow charging to start on plug-in, and support methods such as Plug & Charge. Those sit with the charge key rather than the location — [Charge key authentication](/capabilities/access/charge-key-authentication) covers them.
## How the settings combine
The mechanisms follow a clear order of precedence, and it's worth holding the whole picture in view, since a single setting rarely tells you who can charge.
On a **public** location, any registered charge key can charge. If you've set [opening hours](/capabilities/connection/location-configuration#opening-hours), that holds during open hours; outside them, the site narrows to drivers whose charge key is in a bound charge key group, or who hold a voucher.
On a location that **isn't public**, an ordinary charge key is declined. Only two things get a driver in: membership of a charge key group bound to the location, or a valid voucher.
Vouchers and charge key groups always grant access. They override the public setting and opening hours alike — so a driver with either can charge at a location even when it's private or closed to the public. Treat them as the deliberate exceptions to a location's general rules.
## Dependencies & limitations
* **Vouchers and charge key groups override location settings.** They're absolute grants, so a location's public setting and opening hours don't restrict a driver who holds one. Keep that in mind when you rely on opening hours to limit access.
* **A non-public location declines ordinary charge keys.** Only a bound charge key group or a voucher authorises there; a plain registered charge key isn't enough.
* **Residential access works differently.** Private, residential-type charge boxes use their own sharing and app-user mechanisms, set from Spirii Go rather than the location settings here.
## Related
The keys that authorise charging, and the groups that scope them to locations.
Codes that grant access and a set rate, overriding a location's own rules.
How vouchers open access and pricing to specific drivers.
Extend visibility and access to drivers on other networks.
Where a location's publishing settings and opening hours are set.
How a charge key authenticates a session, and the methods a charger accepts.
# Plug & Charge
Source: https://docs.spirii.com/capabilities/access/plug-and-charge
Let drivers charge by plugging in: enable certificate-based Plug & Charge on your chargers, settled through roaming.
Plug & Charge lets a driver start a session by connecting the cable and nothing else. No app, no RFID. You enable it per charge box, and any driver whose vehicle and eMSP contract support it can charge, with the session settled through roaming.
## Overview
Behind that simple experience is an exchange of digital certificates between the car, the charger, you as the operator, the driver's eMSP, and the roaming network. Spirii handles that complexity for you: in Spirii Connect, enabling Plug & Charge on a charge box is a single switch.
The payoff is a smoother arrival for drivers (no app to open or key to find), which tends to lift satisfaction at a location and bring drivers back. You enable the feature; the driver's eMSP supplies the payment contract and the certificate that identifies their vehicle.
## How it works
Plug & Charge is built on Hubject's ecosystem, so a Plug & Charge session is handled as a roaming transaction. Once you enable it on a charge box, that box accepts Plug & Charge from any roaming eMSP subscribed to your Spirii offer in Hubject.
When a driver with a Plug & Charge-capable vehicle and an eMSP contract plugs in, the car and charger exchange certificates (the ISO 15118 standard), the driver is identified, and charging begins on its own. Nothing is tapped or scanned.
For example, a Plug & Charge driver pulls into a location, connects the cable, and charging starts straight away; they never open an app, and the session bills through their own eMSP.
## Enabling Plug & Charge
Before you enable it, two things need to be in place:
* **A validated charge box.** Plug & Charge can be enabled only on charge box models Spirii has validated for it, and the validated set is currently limited. The [models API](/api-reference/chargeboxes-v2/fetches-a-list-of-supported-charge-box-models) flags which models qualify. See [Charger validation](/capabilities/connection/charger-validation) for how models are validated.
* **A roaming-ready location.** The location must have roaming enabled, a tariff, and a roaming tariff set, the same publishing setup that lets it reach any roaming network.
How to enable Plug & Charge in Spirii Connect:
The box needs to be online with every connector in an **Available** state, with no active sessions, because enabling the feature reboots it.
On the **Charge Boxes** tab, open the box's menu and select **Plug & Charge**, then enable it.
The charger reboots and installs its certificates once it's back online. Expect a few minutes. When the box shows **Plug and Charge enabled**, it's ready to receive Plug & Charge drivers.
Only Connect users with the Operator role can enable Plug & Charge.
## Pricing and billing
A Plug & Charge session is priced by the **tariff set on the location** (the same tariff a Spirii app or RFID driver pays) plus any margin the driver's own eMSP adds on top. Because it uses the location's standard tariff, Plug & Charge also carries your advanced pricing, including dynamic pricing and conditional fees. See [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic).
The driver pays through their arrangement with their eMSP, as with any roaming session, and Spirii invoices the eMSP that owns the vehicle's Plug & Charge certificate. The roaming tariff on the location isn't used to price these sessions; it's only there to publish the location to the roaming network.
## Plug & Charge and Autocharge
Both let a driver charge by plugging in, but they're different mechanisms. Plug & Charge uses signed certificates carried by the driver's eMSP contract and settles through roaming, so you don't manage the driver at all. Autocharge identifies a vehicle by its VIN or MAC address as a charge key you issue and own. Reach for Autocharge to give your own fleet plug-in charging on your own sites; Plug & Charge opens your chargers to any eMSP's Plug & Charge drivers. Autocharge and the other charge key methods are covered in [Charge key authentication](/capabilities/access/charge-key-authentication).
## Dependencies & limitations
* **Validated hardware only.** Only charge box models Spirii has validated for Plug & Charge can be enabled, and that set is currently limited.
* **The location must be roaming-ready.** Roaming enabled, a tariff, and a roaming tariff all need to be set before the feature will work.
* **Enabling reboots the charger.** The box must be online with no active sessions, and it goes through a reboot and certificate install that takes a few minutes.
* **Drivers reach it through their eMSP.** A driver can only use Plug & Charge at your charger if their eMSP is subscribed to your Spirii offer in Hubject.
## Related
The roaming setup that Plug & Charge sessions are settled through.
The location tariff that prices Plug & Charge sessions.
The charge box you enable Plug & Charge on.
Autocharge and the other ways a driver authenticates to charge.
Set roaming and the tariffs a Plug & Charge location needs.
# Voucher access
Source: https://docs.spirii.com/capabilities/access/voucher-access
Give a chosen group of drivers access to selected locations at a price you set.
Voucher access lets you open a set of locations to a specific group of drivers (fleet drivers, employees, residents, VIPs) and set what they pay there, without changing your public pricing.
## Overview
A voucher bundles three things:
The known audience the voucher is for: a partner fleet, employees, residents, or a pilot group.
The sites the voucher opens, including ones that aren't on the public network.
What charging costs those drivers there, separate from your public pricing.
You define them once on a **voucher group**, then issue **codes** under it for drivers to redeem. While a code is active, its holder pays the voucher price at the attached locations, and can reach locations that aren't on the public network at all.
It's the tool for any case where a known audience should charge on terms of your choosing: a partner fleet at a negotiated rate, employees or residents at a reduced price, a pilot group with a capped, time-limited code. The common thread is access for a defined group; how you use it is up to you.
## How it works
Setting up voucher access runs in three steps, all under **Vouchers** in Spirii Connect:
Give it a name, pick the customer, and set the price: link a [tariff](/components/commercial/tariffs) (recommended) so pricing stays in one place.
On the group's Locations tab, bind the [locations](/components/charging/locations) the voucher should grant access to. These are where its price applies.
On the Voucher tab, add a single code or autogenerate a batch with a shared prefix, each with an optional max-users cap and expiry date.
You distribute the codes to your group yourself. Spirii doesn't hand them out. A driver redeems one in **Spirii Go** or a branded app (profile → Vouchers → Add new voucher → enter the code), after which the attached locations appear in their app at the voucher price. A voucher can also be linked to a **Spirii charge key**, so the charge key carries the access without the driver entering a code.
For example, an operator opening a depot to a partner fleet creates a group linked to the agreed tariff, attaches the depot, autogenerates a batch of codes with a prefix and an expiry, and sends them to the fleet, without altering the depot's public price.
## Options & configuration
**Pricing.** Set the price with a linked **Tariff**. That's the recommended option, so the voucher controls access while the tariff controls price, and your pricing lives in one place. A **Fixed** price (a flat rate per kWh) or a **Dynamic** price (spot price plus a markup) can also be set directly on the group, but a linked tariff keeps pricing consistent across the platform.
**Code restrictions.** Use **max users** to stop a code being shared beyond the intended group, and **expires at** for time-limited access such as a pilot or a fixed-term agreement. For batches, a clear **prefix** keeps codes easy to recognise and manage.
## When to use it
* A partner or guest fleet you want to admit at a negotiated price, without touching your public tariff.
* Employees or residents who should charge at a reduced rate at your sites.
* A pilot or limited-term group, kept tidy with a capped, expiring code.
## Charge key association
A voucher can be linked to a [charge key](/components/access/charge-keys) as well as redeemed in an app. The link is made on the individual code rather than the voucher group, and it gives that charge key the same terms the group defines: the locations the voucher opens, and what charging costs there.
So the same voucher reaches a driver two ways:
* **Through an app user.** The driver enters the code in Spirii Go or a branded app. That attaches their app user to the voucher, up to its max users cap, and applies the access and price to their account.
* **Through a charge key.** You link the code to a charge key, and any session started with that charge key gets the voucher's locations and price.
In Connect, open the voucher group and find the code on its **Vouchers** tab. The code's **Charge Keys** tab is where you select the charge key to add (charge keys appear as charge keys in Connect).
## Dependencies & limitations
* **Spirii's mobility surfaces only.** Vouchers work in Spirii Go, branded apps, and with Spirii charge keys. They aren't shared with external eMSPs and don't travel over roaming.
* **A voucher overrides the public tariff.** While active, its holder pays the voucher price — not the public price — at every attached location, so be deliberate about who gets a code and where it applies.
## Related
The voucher group and code objects this builds on.
Link a tariff to set the voucher price in one place.
The sites you attach a voucher to.
Link a voucher to a charge key to carry its access.
# Branding
Source: https://docs.spirii.com/capabilities/account/branding
Brand Spirii Connect for your customers, and your locations for drivers.
Branding lets you replace Spirii's logo in Connect with your own, and set the name drivers see for your charging locations.
## Overview
Two settings sit behind branding, and they reach different audiences.
Your logo in place of Spirii's, for everyone who signs in to Connect under your account. Operators only.
The name drivers see for your locations in charging apps and over roaming. Set per customer.
The logo brands the platform your team and your customers work in. The display name brands what drivers see when they find and use your chargers. Neither costs anything — both are included with your account, and both are configured in Connect under **Settings → Branding**, where they sit next to each other.
The Connect logo does not reach drivers. It brands Connect and the emails the platform sends, and nothing in Spirii Go or a branded app. Driver-facing app branding is a separate product.
## The Connect logo
Upload a logo and it replaces Spirii's in the top-left corner of Connect for you, your colleagues, and every customer beneath you in the hierarchy when they sign in. It also appears on emails the platform generates: invitations to new users, password resets, and alert notifications.
Only an Operator can set it, and there is one logo per operator account. A customer cannot override the logo they inherit, so what you upload is what everyone below you sees.
Connect accepts SVG, PNG, JPG, and GIF. A square image of at least 128 × 128 px works best, since the logo renders in a small square area in the top-left corner and on email headers. You can remove it at any time to return to Spirii's.
**When it helps.** A CPO that gives site owners logins to manage their own chargers can put its own logo in Connect, so the platform reads as part of the CPO's service rather than a third party's. The same logo carries onto the invitation and password-reset emails those users receive, which is often their first contact with the platform.
## The charging app display name
A customer's name in the platform is its legal or registered name, which is not always the name it trades under. The display name overrides it for drivers. A customer registered as `Acme Inc.` can have its locations appear as `Acme Charging`.
### How the name is resolved
Where no display name is set, the platform falls back through a chain, and the chain differs by surface:
| Where the name appears | Order of precedence |
| - | - |
| Spirii Go and branded apps | Display name → customer name → operator name |
| Direct roaming connections, over OCPI | Display name → operator name → Spirii |
| Roaming via Hubject | Spirii |
Roaming connections publish at operator level. Spirii is the operator of record and you sit beneath it as **sub-operator**, which is the field a roaming partner reads to attribute a site to you. The name a partner receives is the one set on your own organisation's customer account, and it covers every location you publish, including those owned by customers beneath you. In the apps, those same locations appear under their owning customer's name.
### A worked example
`Rheinstrom GmbH` operates a network and has set the display name on its own customer account to `Rheinstrom Charging`. Beneath it sits a housing association, `Lindenhof Housing`, which owns the chargers at its site and has set its display name to `Lindenhof Charging`.
A driver finding that site sees:
| Surface | Name shown |
| - | - |
| Spirii Go, or Rheinstrom's branded app | `Lindenhof Charging` |
| A roaming partner over direct OCPI | `Rheinstrom Charging` |
| A roaming partner via Hubject | `Spirii` |
The housing association's brand reaches drivers in the apps, and roaming drivers see the operator that publishes the site. Worth knowing before a site goes live, so the brand a tenant expects matches what they find.
### Setting a display name
Set it to the brand on the customer's signage and marketing, rather than its registered entity name. Left empty, the platform falls back through the chain above, which means drivers see the registered name including any legal suffix.
Each customer sets its own display name, from the same **Settings → Branding** tab where an operator uploads a logo. Unlike the logo, which only an Operator can set, the display name can also be changed by an Editor. An operator serving several customer brands therefore has one display name per customer rather than one for the network, and the customer has to exist before it can carry one — see [Customer management](/capabilities/account/customer-management) if you need to create one.
**When it helps.** A business registered as a holding company, or with a legal suffix drivers would not recognise, sets a display name so its locations appear under the brand on its signage. Where residents or fleet drivers already know a brand, matching it in the app removes a moment of doubt about whether they are in the right place.
## Dependencies & limitations
**The Connect logo**
* **One logo per operator, inherited downward.** Customers cannot set or override the logo they see.
* **Connect and platform emails only.** Spirii Go and branded apps are branded separately.
**The charging app display name**
* **Names published to roaming depend on the connection.** Direct OCPI connections carry your operator display name; connections via Hubject publish under Spirii. If brand presentation to roaming drivers matters to you, check which connections carry your traffic.
* **Static data republishes on a daily cycle.** A change to a display name reaches roaming partners within 24 hours rather than immediately.
* **Display names apply to presentation.** They govern how a location appears in the apps and to roaming partners, not what appears on receipts or charge detail records (CDRs).
## Related
If you manage several customer brands, [Customer management](/capabilities/account/customer-management) covers creating and structuring the customers each display name belongs to.
Create the customer a display name is set on, and the hierarchy the logo is inherited through.
What a customer is, and the two sides of the relationship it can represent.
Who in your organisation can reach these settings.
Where a location is assigned to the customer whose display name it carries.
# Customer management
Source: https://docs.spirii.com/capabilities/account/customer-management
Create and structure the customer organisations in your network — their owners, hierarchy, and the details that drive location ownership and billing.
Customers are the organisations that make up your network: the site owners, fleet operators, and sub-operators you serve or sit above. Managing them is how you build that structure: who owns whom, who owns which locations, and who gets billed for what.
## Overview
A customer is a business or private entity in your network. The [Customers component](/components/organisation/customers) covers what a customer is and the two sides it can represent: a site owner whose chargers you operate, or a fleet operator whose drivers you serve. This page is how you create and manage them.
Two things make customers more than a contact list. They form a **hierarchy** (each customer has an owner, and owners can sit above other customers), and that hierarchy is what several parts of the platform lean on: it sets the boundary of a user's data access in [Team Access](/capabilities/account/user-management), it records which customer owns each location, and it's the structure billing and payouts resolve through. You manage customers on the **Customers** page in Spirii Connect, as an Operator or Editor, or through the [Customers API](/api-reference/customer-v2/create-a-new-customer).
## The customer hierarchy
Every customer has an **owner**. You can own a customer directly, or place it under a subsidiary or one of your business customers, and those relationships build the tree that mirrors how your business is structured, whether that's site owners beneath a CPO, sub-operators under a country-level operator, or fleets under an eMSP. One rule constrains the shape: a private customer can't own other customers.
```mermaid theme={null}
graph TD
O(Operator) --> A(Customer)
O --> B(Customer)
O --> C(Customer)
A --> A1(Customer)
A --> A2(Customer)
C --> C1(Customer)
C --> C2(Customer)
```
A user's company and its place in the hierarchy decide whose data they can see; a location is owned by a customer somewhere in it; and financial flows follow it.
Changing a customer's owner restructures the hierarchy automatically, but it does **not** move existing location ownership or financial agreements with it. After a move, check those so billing and payouts still resolve to the right place.
## Creating a customer
Only Operators can create customers. If you're setting up a location that you don't own directly, create its customer first so you can assign it as the owner.
Every customer needs an owner: you, a subsidiary, or one of your business customers. This is what places the customer in the hierarchy.
Give the customer a **name** (a company name for a business customer such as Acme Inc., a person's full name for a private one), a **type** (business or private), and an **origin country** (a customer belongs to one country). Use the **external ID** to carry your own reference for the customer into billing or internal systems.
Every customer needs a contact person Spirii can reach about invoicing or account matters. Customers created through onboarding flows have this filled in for you.
If Spirii provides financial services to the operator that owns the customer, the billing and payout sections are required: billing address and VAT number, invoice format, payout bank details, and the currency and language invoices are sent in. If no financial services are involved, these are optional and informative only.
## Editing and deleting
You can edit almost any field on a customer after it's created, from the overview table or the customer's own page, with one exception: the payment method, which is fixed to invoice.
Deleting is a soft delete, available to Operators, and only when a customer owns no locations and no other customers. That's a deliberate guard: a customer with dependencies can't be removed until they're reassigned or cleared.
Customers are kept in sync with the Spirii Business Platform, so deleting a customer in Connect deletes it in the Business Platform as well, and the other way round.
## Dependencies & limitations
* **Roles.** Operators can create, edit, and delete customers; Editors can view and edit but not create or delete. Both can see the customers under their account.
* **Every customer has an owner.** A customer can't exist outside the hierarchy, and a private customer can't own other customers.
* **Delete needs a clean customer.** A customer can only be deleted once it owns no locations and no other customers.
* **The payment method is fixed.** Billing is by invoice and can't be changed after creation.
* **Orders live in the Business Platform, and agreements are shared with it.** Orders aren't managed from Connect. Agreements can be edited in Connect or the Business Platform. An owner change doesn't cascade to either.
## Related
What a customer is, and the two sides of the relationship it can represent.
Create, read, update, and delete customers programmatically.
How the customer hierarchy sets the boundary of a user's data access.
Where a location is assigned to the customer that owns it.
# Impersonation
Source: https://docs.spirii.com/capabilities/account/impersonation
See Spirii Connect with one customer's data, without leaving your own account.
Impersonation filters Connect down to a single customer's data, so you see the locations, chargers, and records that customer sees.
## Overview
Supporting a customer is easier when you are looking at what they are looking at. Impersonation gives you that: pick one of your customers, and Connect hides everything that is not theirs.
It is available to users with the Operator role. Impersonation stays active across every page in Connect until you stop it, so a yellow border frames the screen throughout, with the selected customer named at the bottom next to a **Stop** control.
## What changes, and what does not
**Data is filtered.** Locations, chargers, sessions, tariffs, and records narrow to the customer you selected, along with any customers beneath them in the hierarchy. Everything else is hidden.
**Your permissions are not.** You keep your own access the whole time. If your role reaches a setting your customer's role cannot, that setting is still there in front of you.
If a customer reports that they cannot find something, impersonating them will not reproduce it — you will still see it with your own access. Check their role in [Team access](/capabilities/account/user-management) instead.
## Starting and stopping
Click your name at the bottom left of the menu and choose **Impersonate**, then pick a customer from the list. The yellow border appears and Connect reloads into that customer's view.
To return to your own view, use the **Stop** control at the bottom, next to the customer's name.
## When to use it
**Reproducing what a customer is looking at.** The original case, and still the most common one. A customer describing a report or a list they cannot make sense of is far easier to help when you are seeing the same rows.
**Working within a customer's context.** Some operations act on the owning customer rather than on you, so impersonation is how you reach them. Selecting a customer's charge boxes for a [firmware update](/capabilities/operation-monitoring/firmware-management) is one — the list only offers charge boxes belonging to whoever you are impersonating.
**Narrowing an operational view.** On pages that span your whole network — the [Connectors page](/capabilities/operation-monitoring/live-status-tracking), the [Monitoring list](/capabilities/operation-monitoring/faults-and-alerts) — impersonating a customer scopes the rows to one estate.
## Dependencies & limitations
* **Operator role only.** Other roles do not have the option.
* **Data, not permissions.** Impersonation filters what you can see. It does not reduce what you can do, so it will not reproduce a customer's access problem.
* **Actions take effect.** This is not a preview mode. Work you do while impersonating is real work on that customer's data.
* **One customer at a time.** You select a single customer, and their descendants come with them.
## Related
If a customer's problem turns out to be about access rather than data, their role is where to look.
Roles, and what each one can reach.
The hierarchy that decides which customers you can impersonate.
What a customer is, and the two sides of the relationship it can represent.
An operation that acts in the owning customer's context.
# Roles and permissions
Source: https://docs.spirii.com/capabilities/account/roles
Compare the roles and pick the right one for each user you invite to Spirii Connect.
A role sets what a user can do in Connect: which pages they can open, and which actions they can take on the data their customer scope already gives them access to.
## Overview
Every Connect user has a customer and a role. The customer decides *which* data they see; the role decides what they can do with it.
Five roles form a general ladder, from full edit rights down to read-only. Three more are shaped around a specific job and sit outside that ladder. A user can hold more than one role at a time.
You assign roles in [Team Access](/capabilities/account/user-management), which also covers who is allowed to assign which role.
## Choosing a role
Start from the job, not the role name.
| If someone needs to | Give them |
| - | - |
| Run the account end to end, including sites, billing, settings, and firmware | Operator |
| Work the data day to day — pricing, drivers, charge keys — without creating sites or chargers | Editor |
| Support drivers: look up sessions, restart a charger, raise a ticket | Supporter |
| Maintain pricing only, with no access to drivers or operations | User |
| Manage a fleet's drivers, charge keys, and charging spend | Fleet Manager |
| Run the chargers at one site day to day | Depot Manager |
| See everything and change nothing, for reporting or oversight | Viewer |
| Commission chargers on site | Installer |
## The general roles
Operator, Editor, Supporter, User, and Viewer cover most people you invite. They overlap heavily, so the differences are easier to read as a table than as descriptions. A dash means the role has no access to that area.
| Area | Operator | Editor | Supporter | User | Viewer |
| - | - | - | - | - | - |
| Locations | Create, edit, delete | Edit, delete | View | View | View |
| Charge boxes and EVSEs | Create, edit, delete | View | View | View | View |
| Remote commands | Run | Run | Run | — | — |
| Charge box configuration and Plug & Charge | Edit | — | — | — | — |
| Scheduled charging | Set | Set | — | — | — |
| Power management | Edit | View | — | — | — |
| Tariffs | Create, edit | Create, edit | View | Edit | View |
| Vouchers | Create, edit | Create, edit | View | Create, edit | View |
| Charge keys | Create, edit | Edit | View, assign | View | View |
| Drivers | Edit, delete | Edit, delete | Edit | — | View |
| Sessions and charge detail records (CDRs) | View | View | View | View | View |
| SLAs | Create, edit | View | View | — | — |
| Operations Center | View | — | — | — | — |
| Support tickets | Create, close | Create | Create | Create | View |
| Payments and payment terminals | Manage | — | — | — | — |
| Settings and branding | Edit | — | — | — | — |
| Team Access | Manage users | Manage users | — | View | — |
Charge keys appear as charge keys in Connect's interface; the two mean the same thing.
### Operator is for your own team
Keep Operator for colleagues at your own company, on the operator side of the account. Users scoped to a customer should hold Editor or below, however senior they are on their own side: an Operator can change billing, settings, and pricing everywhere their scope reaches.
That makes the Operator and Editor boundary the one worth knowing. Creating locations and charge boxes, charge box configuration, payment terminals, SLAs, settings, branding, and the Operations Center all stay with Operator. An Editor does the rest, including editing and deleting locations. So an Editor who needs a new charger on a site has to ask, which is usually the point: adding a charger changes what that site bills.
## Specialist roles
These three exist for one job each. They don't sit above or below the general roles, and they pair well with one — an on-site engineer who also fields driver calls might hold Depot Manager and Supporter together.
For a fleet operator managing their own drivers and charging rather than a charging network.
* View drivers, charge keys, and vouchers
* View CDRs for the fleet's charging
* View the charge map
* Create, edit, and cancel bookings, and view bookable locations
* Review, adjust, and approve home charging expense reports
* Add and edit reimbursement rates on employees' home locations
Approving and rejecting bookings stays with the Operator.
For someone running the chargers at a single site, with no reason to touch pricing, drivers, or the wider network.
* View the Connectors page
* Run remote commands on the site's charge boxes
For an installation partner commissioning hardware, with as little else as possible.
* Look up an order and create charge boxes from it
* View the locations they work on
* Run remote commands and read the OCPP log while testing a unit
* Set a temporary EVSE status while a unit is being worked on
* View support tickets
An Installer creates charge boxes but not locations, so the site has to exist before they arrive.
[Installers](/capabilities/automation/installers) covers bringing an installation partner into Connect and how their work fits the commissioning sequence.
## Holding more than one role
A user can hold several roles at once, and their access is the sum of them. Pairing Depot Manager with Supporter gives someone the site's chargers plus driver support, without handing over the whole account.
Combine roles when no single one fits the job. It's the better answer than moving someone up the ladder to reach a single feature they need.
## Dependencies & limitations
* **The roles are fixed.** They're shaped around how charging teams actually divide the work, so the set covers the common shapes without configuration. Where one role doesn't fit a person, combine two.
* **Scope data with the customer hierarchy, and features with the role.** A role applies across everything the user can already see, so narrow their reach by placing them under the right customer rather than by picking a smaller role. See [Customers](/components/organisation/customers).
* **Role assignment follows the hierarchy.** You can assign any role at or below your own, so an Operator can appoint another Operator and an Editor can build out a team of Editors and below. Covered in [Team Access](/capabilities/account/user-management).
## Related
Invite users, scope their data access, and assign roles.
The company hierarchy that decides which data a user can reach.
Who can charge at a location, as opposed to who can administer it.
What an invited user does to set their password and MFA.
# User management
Source: https://docs.spirii.com/capabilities/account/user-management
Invite colleagues and customers to Spirii Connect, scope which data they see, and set what they can do with roles.
Team Access is where you control who can use Connect, both your own colleagues and your customers, and what each person can see and do. You invite them, scope their access to the right data, and give them a role that decides which features they can use.
## Overview
Access in Connect has two independent dimensions, and every user has both:
| Dimension | What it controls | Set by |
| - | - | - |
| Customer | **Data access**: which locations, tariffs, charge keys, and records a user can see | The user's company and its position in the customer hierarchy |
| Role | **Feature access**: what a user can do with the data they can see | One or more of eight roles |
A user tied to a customer sees that customer's data; a colleague at your own company sees yours. Their role then decides whether they can only view it, edit it, or administer the platform. You find Team Access in the bottom-left of Connect, under your own name.
The customer side draws on the [Customers](/components/organisation/customers) model, where a user's company and the customers beneath it in the hierarchy set the boundary of what they can reach. This page is about granting people access within that boundary and choosing what they can do.
## Roles
A role sets which features and actions a user has across the data they can access. There are eight, ranging from Operator, which edits everything, down to narrow roles built for one job, such as Installer. A user can hold more than one at a time, and their access is the sum of them.
What each of the eight roles can do, side by side, and how to pick one.
### Who can assign which role
Roles sit in a hierarchy, and you can only assign a role at or below your own. An Editor can invite people as Editor, Supporter, User, or Viewer, but cannot make anyone an Operator — only an Operator can do that. The same limit applies when you change an existing user's role.
This is worth checking before you delegate user management. Handing someone Editor so they can onboard their own team means they'll come back to you every time a new Operator is needed.
## Inviting a user
The same flow invites a colleague or a customer; the difference is which customer you scope them to.
In the bottom-left of Connect, click your name, then select **Team Access**.
Choose **Add new user** and enter their email address.
Leave the customer as your own company for a colleague, or set a specific customer, such as Acme Inc., to give their user access to only that customer's data.
Pick the role that matches what they need to do: a colleague running a site might be an Editor, a customer checking their own usage a Viewer. Where no single role fits, assign two — see [Roles](/capabilities/account/roles).
The user receives an email inviting them to set a password. On first login they'll also set up multi-factor authentication.
## Resetting a user's MFA
Multi-factor authentication is required for every Connect user. When someone loses access to their authenticator (a lost or replaced phone, or a reinstalled app), an **Operator** or **Editor** resets it from Team Access: find the user, open the actions menu, and choose **Reset MFA**.
Resetting MFA signs the user out of every active session, and they must set up MFA again with a new code on their next login. No notification is sent automatically, so tell them yourself, and verify their identity first, since a reset is what an attacker would want.
## Dependencies & limitations
* **Only Operator and Editor can change users.** Both can invite users, edit them, and reset MFA. A User can open Team Access and see who has access, but can't change anything. Every other role has no access to the page at all.
* **You can't assign a role above your own.** An Editor cannot create an Operator.
* **MFA can't be skipped.** Every user sets up multi-factor authentication on first login; it's mandatory.
* **Data access is bounded by the hierarchy.** A user can only ever reach data for their company and the customers beneath it; you can't grant access outside that boundary. See [Customers](/components/organisation/customers).
* **Invites expire.** An invitation needs to be accepted within a couple of days before it lapses and has to be resent.
## Related
What each of the eight roles can do, side by side.
The company hierarchy that sets the boundary of a user's data access.
Who can charge at a location, as opposed to who can administer the platform here.
What an invited user does to set their password and MFA and get into Connect.
# Installers
Source: https://docs.spirii.com/capabilities/automation/installers
Bring installation partners into Spirii Connect to get your chargers live.
An installer needs enough access in Connect to bring a charge box live, and no more. The Installer role is scoped for exactly that.
## Overview
An installation is the point where an order becomes a working charger: hardware mounted, configured, registered in Connect, and confirmed to charge. That work usually falls to a third party who works across several operators' sites and does not need to see what you charge for energy.
Where the installation came from an onboarding flow, the whole sequence runs without anyone coordinating it by hand.
```mermaid theme={null}
flowchart LR
O("Order completed") --> R("Installation request\nrouted by postcode")
R --> I("Installer registers\nthe charge box")
I --> A("Charge box comes online") --> E("Order fulfilled email\nto the customer")
```
See [Onboarding flows](/capabilities/automation/onboarding-flows) for the ordering half and the email templates behind it.
## The Installer role
You invite an installer through Team Access and give them the **Installer** role, which reaches what an installation needs:
* Look up locations
* View, add, and configure charge boxes and connectors
* Send remote commands to a charge box
* View sessions, so an installation can be verified on the spot
It does not reach tariffs or pricing.
Access is scoped when you invite them. An installer can either reach every customer and location under your account, or a single customer and that customer's locations. Choose the narrower option for a partner working on one client's estate, and the broader one for a partner covering your whole territory.
## Before an installer arrives
Three things need to be in place, and all three are yours to arrange.
**A validated charge box model.** Spirii validates whether a model can connect to the platform at all. Confirm the model is validated before the hardware ships, because an unvalidated box cannot be registered.
**The charger's OCPP configuration.** Whoever configures the charger sets these on the unit itself:
| Setting | Value |
| - | - |
| OCPP version | 1.6J |
| OCPP endpoint | `wss://ocpp.spirii.com` |
| Charge box identity | A unique ID following eMI3 syntax. See [Charge boxes](/components/charging/charge-boxes) for the form it takes |
**A charge key for testing.** An installer verifies the installation by running a real session, so issue them an RFID charge key to test with.
## What an installer does in Connect
From **Locations**, search for the site by address. In Nordic markets an installer can also look a site up by its order ID.
On the location's **Overview** tab, enter the **main fuse capacity** of the installation. Load balancing distributes power within that figure, so a site with more than one charger depends on it being right.
On the **Charge boxes** tab, add a charge box: its type from the list, or **Other** where the model is not listed; the serial number printed on the unit; and the charge box identity.
A correctly configured charger reaches the platform within five to ten minutes. Once it sends its first boot notification, Connect fills in the vendor, model, firmware, and connectors on its own. Some models need a reboot before they retry.
Start a session with the charge key you issued, and confirm it appears in Connect. Authentication is enabled on every charge box by default, so a charge key that is bound correctly will start the session.
The charge box identity entered in Connect has to match the OCPP identity configured on the charger exactly. A mismatch is the most common reason a correctly installed charger never appears online.
## Dependencies & limitations
* **Installers cannot see tariffs or pricing.** The role reaches locations, charge boxes, connectors, and sessions.
* **Access is scoped per installer.** Each one covers either every customer under your account or a single customer's locations.
* **Only validated models can be registered.** Spirii validates whether a charge box model can connect to the platform.
* **Moving or recreating a charge box is an operator action.** An installer cannot move a box between locations or recreate a deleted one.
## Related
Invite your installer through Team Access, then hand them the OCPP values above.
The order that triggers an installation request, and the emails around it.
Inviting an installer and scoping what they reach.
What a charge box is, and how identity and connectors work.
The commands an installer can send during commissioning.
# Onboarding flows
Source: https://docs.spirii.com/capabilities/automation/onboarding-flows
Sell charging hardware and subscriptions online, to consumers or to businesses.
An onboarding flow is a branded ordering experience for charging hardware, subscriptions, and charge keys. When a customer completes one, the platform creates and connects everything their setup needs.
## Overview
Getting a driver charging at home takes a customer record, a location, an app account, an order, and someone to install the hardware. An onboarding flow produces all of it from one order the customer places themselves.
The same flow serves whoever is ordering:
They order a [charge box](/components/charging/charge-boxes) and a subscription, and arrive with an app account already attached to their address.
The employer's flow presents the products the scheme covers, and the resulting records sit under the employer.
A flow set to business customers collects company details and invoices rather than taking a card.
Onboarding flows are configured in the Spirii Business Portal rather than in Spirii Connect.
## What a flow creates
A completed order produces the records a charging setup depends on, already bound together.
Assigned to the owner and the agreement you set on the flow.
For the address they gave, residential where the order is for a home.
Attached to that location, so a driver ordering a home charge box can control it from the app as soon as it is live. For a business ordering chargers for a site, no app user is needed.
Carrying the products they chose, which is what the installation and activation steps work from.
Associations can be configured too, so an ordered RFID [charge key](/components/access/charge-keys) arrives already bound to the customer.
```mermaid theme={null}
flowchart TD
O("Order completed") --> C("Customer")
O --> L("Location")
O --> AU("App user")
O --> CK("Charge key")
C --> L
AU --> L
CK --> C
```
An employee ordering a home charge box through `Acme Inc.`'s flow therefore becomes a private customer owned by Acme, with a residential location at their own address and an app account attached to it.
## The ordering experience
Optional. A marketing page ahead of the order itself, with your own imagery and sales copy, for flows that need to sell before they collect.
What a customer can order, usually one item at a time: a charge box model, a charge key, a subscription. Where it helps, several items can be bundled so they present as a single package. For each, you decide whether it is mandatory or an optional add-on, whether its price is shown, and whether a customer can order more than one.
The fields a customer fills in, arranged in groups with their own headings and explanations. You choose each field's type, label, help text, and whether it is required.
Checkboxes a customer accepts before ordering, each with its own text and links. Some block the order until accepted; others, like a newsletter opt-in, do not.
Card or invoice, set per flow. Card payments are processed through Stripe with Spirii as the merchant, so Spirii's name appears on the customer's statement and handles any dispute. On an invoice flow, the customer agrees to be invoiced instead.
A success page with your own imagery and welcome text, or a redirect back to your own site.
### Flow-level settings
| Setting | What it decides |
| - | - |
| Owner | The customer every sign-up is assigned to. Your own account, or a reseller's |
| Agreement | The terms and transaction calculation applied to every customer the flow creates |
| Market type | Whether the flow creates private or business customers |
| URL | The address the flow lives at |
| Language | The language of the flow's buttons, help text, and error messages |
| Branding | Logo, colours, and text across the flow, its landing page, and its confirmation page |
| Success URL | Where a customer lands after paying, if you want them returned to your own site |
## Automated follow-up
A completed order triggers the emails that move the setup along. Each is a template you can write yourself, with its own subject, body, footer, and an optional BCC address for your own records.
| Email | Goes to | Fires when |
| - | - | - |
| Order confirmation | Customer | The order completes |
| Installation information | Customer | Two hours after the order completes |
| Installation request | Installation partner | The order completes |
| Order fulfilled | Customer | The charge box is activated after installation |
| Cancellation confirmation | Customer | A subscription is cancelled |
Order fulfilment is driven by the [charge box activating](/capabilities/connection/charger-activation), so a customer is told their charger is live as soon as it is.
Templates can be written once for a flow, or varied per [installation partner](/capabilities/automation/installers) where different partners need different instructions. Every email the platform sends is logged, so you can see what a customer received and when.
Installation requests route by postcode. Each installation partner has a contact address and a postcode range per flow, so an order reaches whoever covers that area without anyone forwarding it.
An installation partner receives installation requests only for the postcode ranges assigned to them. A partnership with no range set receives none.
## Integration options
You can hand the whole experience to Spirii, keep the storefront and hand over the rest, or build everything and use the platform for what happens after the order.
| | You build | Spirii provides |
| - | - | - |
| **Hosted flow** | Nothing | The whole ordering experience, at your URL and in your branding |
| **Hosted payment page** | The ordering interface on your own site | Card payment, and the records and automation behind it |
| **API and webhooks** | The ordering interface and the payment | The records, the automation, and order events pushed back to you |
The hosted flow is the fastest route to live. The API route suits a partner with an existing website and a checkout they already trust, who wants the automation without a second storefront. The middle option sits between them: your storefront, Spirii's payment page, no card handling on your side.
## Set up
Spirii configures onboarding flows as a service, which is how most partners run them. You can also have your own login to the Business Portal, giving you full configuration of your flows and the ability to manage the orders that come through them.
Customers themselves are managed in Connect. See [Customer management](/capabilities/account/customer-management) for the hierarchy every flow assigns its sign-ups into.
Talk to your account manager to get started.
## Dependencies & limitations
* **Flows are configured in the Business Portal.** Onboarding flows are not set up in Connect, although the customers and locations they create appear there.
* **Postcode ranges gate installation emails.** A partnership without a range sends nothing.
* **Spirii is the merchant for card payments.** Card orders are processed through Stripe under Spirii, which also covers disputes and refunds for them.
* **Payment is card or invoice.** Both are set per flow rather than chosen by the customer.
## Related
The installation request an order sends is the start of the installer's side of the process.
What happens after an installation request, and what an installer does in Connect.
The hierarchy a flow assigns its customers into.
The driver record a flow creates, and how it attaches to a location.
What a location holds, including the residential ones a flow creates.
# Billing and payout flows
Source: https://docs.spirii.com/capabilities/billing-payouts/billing-and-payout-flows
Who collects, who invoices, and who pays out, across every channel on the platform.
Every charging session ends with money moving from the driver to you, with Spirii in the middle handling acquiring, VAT, settlement, and payouts. How it plays out depends on who operates the chargers, who owns the site, and whether Spirii holds the acquiring agreement.
## The transaction flow
The driver pays Spirii directly at the tariff you've set, using the app, a contactless terminal, or a stored payment method.
Spirii charges the driver's payment method, applies the correct VAT for the charger's country, and issues a receipt.
At the end of the billing period, Spirii pays you for the energy consumed via a self-billing invoice, net of platform and payment fees.
The commercial relationship runs between the driver and Spirii, and between Spirii and you. You do not invoice roaming partners or eMSPs for sessions Spirii collected on, and they do not invoice you.
How each payment channel (app, terminal, charge key, and roaming) moves money into your account.
## Payment channel comparison
Spirii supports four payment channels for CPOs and site owners. Each captures a different type of driver and requires different infrastructure. Most public CPOs enable several channels on the same location.
| | In-app | In-person | Charge key billing | Roaming |
| - | - | - | - | - |
| **Driver action** | Start session in app | Tap card or phone on terminal | Tap RFID card or virtual charge key | Start via their eMSP's app or physical charge key |
| **Account required** | No, but the app is needed | No | Yes (fleet/eMSP account) | Yes (with their eMSP) |
| **Who is the merchant** | Spirii (always) | Spirii (turnkey) or CPO (PAAS) | Spirii | Spirii |
| **Who gets invoiced** | Driver (card charge) | Driver (card charge) | Fleet company or eMSP (monthly) | Roaming partner (monthly) |
| **VAT reported by** | Spirii | Spirii (turnkey) or CPO (PAAS) | Spirii (Full Service) or CPO | Spirii |
| **CPO hardware required** | None | Payter Apollo terminal | RFID reader on charger | None (uses existing infrastructure) |
| **CPO payout timing** | Following month | Following month | Following month | Same month as roaming partner is invoiced |
| **Receipts** | In-app (digital) | Terminal printout or digital | Monthly invoice to fleet | Via roaming partner's app |
## Who pays whom
These are the platform's roles seen from the money side. For what each one is, see [Platform overview](/platform-overview).
| Party | Where they sit in the money flow |
| - | - |
| **Driver** | Pays Spirii at the moment of charging, by card in an app or at a terminal |
| **CPO** | Paid by Spirii each month by self-billing invoice, for the energy consumed on their chargers |
| **Site owner** | Paid by Spirii directly, where a revenue share is configured on the location |
| **eMSP** | Invoiced by Spirii for the charging its drivers use |
| **Fleet** | Invoiced by Spirii monthly, one bill covering all its drivers' charging |
| **Roaming partner** | Invoiced by Spirii for inbound sessions, and invoices Spirii for outbound ones |
| **Spirii** | Collects from drivers, eMSPs, fleets, and roaming partners, and pays CPOs and site owners |
## Who is the merchant
When Spirii acts as Merchant of Record (MoR), it buys the energy from you and resells it to the driver at the moment of the transaction. You are paid for the energy, and Spirii carries what comes with being the seller.
Spirii is the MoR on in-app, charge key, and roaming sessions, and on terminal sessions where it holds the acquiring agreement.
* Acquiring and card processing (via Stripe and other PSPs)
* Chargebacks, disputes, and refunds
* PCI-DSS compliance for the cardholder data environment
* VAT calculation and local reporting in each country of operation
* Automated digital receipts to drivers
* Pre-authorisation and capture on the driver's payment method
* Setting the charging tariff
* Providing the physical infrastructure (chargers and locations)
* Receiving your monthly payout from Spirii
### VAT
Spirii reports and remits VAT in each country where your chargers operate. Your payout is net of VAT: the VAT collected from the driver is not passed on to you, and goes directly to the relevant tax authority instead.
### When you are the merchant
In PAAS (Platform as a Service) mode you bring your own acquiring agreement and stay the MoR for payment terminal sessions. On those sessions:
* Card funds reach you directly from your payment service provider (PSP)
* You carry PCI-DSS self-assessment as a merchant
* You handle disputes and refunds for your drivers
* You report VAT yourself
* You manage peer-to-peer roaming agreements and settlement with eMSPs
* You manage charge key billing and settle your own mobility sessions
Spirii still provides the platform, the POS software, and the session data, but does not touch the financial flow for those sessions.
## Common setup scenarios
How the parties relate, and how money flows between them, depends on who operates the chargers and who owns the site. Each of these has a page of its own.
The CPO operates the chargers and accepts payments. Spirii collects revenue from drivers across app, terminal, and roaming sessions, and pays the CPO.
```
Driver → pays Spirii → Spirii pays CPO
```
A site owner (landlord, retailer), also called a charge station owner or CSO, owns the location the CPO operates on. Spirii splits the payout and pays each party directly, on a percentage or per-kWh share you set in Spirii Connect. See [Revenue sharing](/capabilities/billing-payouts/revenue-sharing).
```
Driver → pays Spirii → Spirii pays CPO + CSO
```
A fleet gives charge keys to its employees, and Spirii invoices the fleet monthly for everything they charge. An eMSP can hold the billing relationship with its own fleet customers instead, in which case Spirii invoices the eMSP only for sessions on chargers it does not operate as a CPO. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing).
```
Employee charges → Spirii invoices fleet company → Spirii pays CPOs
```
A fleet reimburses employees for electricity used at home. Spirii produces the expense reports, and payment runs through the fleet's payroll or a licensed PSP. See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement).
## Dependencies & limitations
* **Payout timing is not uniform.** App, terminal, and charge key revenue pays out the following month. Roaming pays in the same month Spirii invoices the roaming partner — so a month's income arrives in two pieces.
* **Not every session earns a payout.** Sessions under 0,2 kWh, sessions running past seven days, free and voucher charging, and terminal sessions where you hold the acquiring are all excluded. The specification file with each payout names the reason per session. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **Fees are not netted line by line.** The self-billing invoice carries your revenue; Spirii's platform and payment fees arrive on a separate invoice. Neither document is the full picture on its own.
* **Spirii invoices your fleet customers only at Full Service.** Under Invoice Data Service you invoice them yourself from data Spirii aggregates, and under No service Spirii records the session and settles roaming only. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing).
* **Spirii does not pay out ahead of the funds.** Your payout follows the money Spirii has collected, so it does not carry cash flow risk on your behalf.
## Related
Spirii is always the MoR for app-based charging sessions.
Choose between Spirii acquiring (turnkey) and your own acquiring (PAAS).
How to read a self-billing invoice and reconcile it against Connect.
# Billing as a service
Source: https://docs.spirii.com/capabilities/billing-payouts/billing-as-a-service
Having Spirii invoice your customers for the services you sell alongside charging.
Spirii can invoice your customers on your behalf for services beyond charging revenue: subscription fees, charge point management fees, or home charging reimbursement under your own brand. You define the pricing and the service terms.
## Overview
Charging revenue is not the only thing a CPO bills for. Subscriptions, management fees, and reimbursement services each need invoicing — and each is a billing run someone has to build, then keep running. Spirii can run them for you.
It is not self-serve. Billing as a service is configured with Spirii during onboarding or on request.
## What Spirii can invoice for
Spirii generates the invoice, attaches the relevant session data as a CSV, and sends it to your customer's billing contact.
* **Subscription access fees.** A monthly charge for using your charging network.
* **Charge point management or maintenance fees.** Billed to corporate clients.
* **Home charging reimbursement services.** Invoiced to the fleet company, including the [company car management fee](/capabilities/billing-payouts/home-charging-reimbursement).
* **Per-transaction or per-kWh fees.** Billed to business accounts.
## Distributing revenue, not just billing it
Spirii can also route money outward on your behalf: paying each site owner their share directly, and splitting payouts across separate legal entities where you operate through national subsidiaries. Both run on the financial agreement attached to each location, rather than on anything specific to this service. See [Revenue sharing](/capabilities/billing-payouts/revenue-sharing).
## Set up
Its type, its frequency, and its pricing.
In the Business Portal, so invoices resolve to the right entity.
On the relevant operator in Spirii Connect. This is what decides whether Spirii invoices your customers or hands you the data to invoice them yourself. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing).
One per customer, so each invoice reaches a person who expects it.
Contact your Spirii account representative to get billing as a service configured.
## Dependencies & limitations
Billing as a service is built for B2B relationships, and the boundaries follow from that.
* **No manual invoicing to private drivers.** Spirii processes B2C payments automatically by card. A one-off invoice emailed to an individual driver stays yours to raise.
* **No dedicated payment processing accounts.** The payment infrastructure is standardised, so a single partner cannot have its own arrangement opened for it.
* **Prices come from tariffs set in Connect.** An invoice cannot be priced by an external system after the session has run.
* **No payout ahead of the funds.** Spirii pays out what it has collected, and does not carry cash flow risk on your behalf.
* **No custom development.** The service runs on existing platform capabilities rather than bespoke billing logic.
## Related
Distributing revenue across site owners and subsidiaries.
Billing service levels, and how fleet sessions are invoiced.
The reimbursement service you can invoice a fleet company for.
Who collects, who invoices, and who pays out across every channel.
# Billing automation
Source: https://docs.spirii.com/capabilities/billing-payouts/billing-automation
How the billing engine turns finished charging sessions into the month's invoices and payouts.
Spirii's billing engine reads every CDR as it arrives and works out who owes money, who is owed money, and which document each session belongs on. What lands at the end of the month is a reconciled set of invoices, self-billing invoices, and expense reports — with no billing infrastructure for you to build.
## How it works
The engine runs continuously. As sessions complete and their CDRs are finalised, it evaluates each one against the billing configuration for your account and adds it to the document it belongs on for that period.
```mermaid theme={null}
flowchart TD
A("CDR finalised") --> B("Billing engine evaluates it")
B --> C("Invoice")
B --> D("Self-billing invoice")
B --> E("Expense report")
```
## What the engine decides
| Decision | The options | What drives it |
| - | - | - |
| Who to invoice | A fleet company, an eMSP, a roaming partner, or the driver directly | The session's payment method, and the billing service level set on the operator |
| Who to pay | The CPO, the site owner, a subsidiary, or a split between them | The financial agreement attached to the location |
| What to produce | An invoice, a self-billing invoice, or an expense report | Which party is being billed, and which is being paid |
## The documents it produces
| Document | Who receives it | What it covers |
| - | - | - |
| **Invoice** | A fleet company, an eMSP, or a roaming partner | Consumption billed after the fact. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing) and [Roaming settlement](/capabilities/billing-payouts/roaming-settlement) |
| **Self-billing invoice** | You, as CPO or site owner | Revenue Spirii collected on your chargers. See [Understanding your payout](/capabilities/billing-payouts/payouts) |
| **Expense report** | A fleet company, itemised per employee | Home charging to reimburse. See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) |
Charge key sessions aggregate per billing customer across the period, so one invoice covers every session their drivers ran, with a specification attachment itemising each. Roaming sessions are billed from the CDR data exchanged with the partner over Hubject or OCPI.
## Dependencies & limitations
* **A session is billed once its CDR is final.** The engine works from finalised records, so a session still running is not on any document yet.
* **Late sessions land in the earliest open period.** A charger that was offline syncs its sessions later. Those join the earliest billing period still open, which is the current one if their own has closed.
* **Not every CDR earns revenue.** Sessions below the energy threshold, sessions running past seven days, free and voucher charging, and several other cases are excluded from the payout. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **Documents split by country and currency.** Each supplier receives one document per country and per currency, rather than a single combined document across markets.
* **What Spirii invoices depends on the billing service level.** At Full Service Spirii invoices your customers directly; at the other levels it produces the data and you invoice them. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing).
## Related
How to read the self-billing invoice and reconcile it against Spirii Connect.
Who collects, who invoices, and who pays out across every channel.
How fleet and eMSP sessions are aggregated onto one monthly invoice.
How cross-network sessions are invoiced and settled.
# Charge key billing
Source: https://docs.spirii.com/capabilities/billing-payouts/charge-key-billing
Consolidated monthly invoicing for fleet drivers using RFID cards or virtual charge keys.
Charge key billing gives a fleet company or eMSP one consolidated invoice each month covering every session their drivers ran, on the Spirii network and on roaming partners alike. Drivers tap and charge. Nobody files an expense claim.
## How it works
A fleet driver starts a session with their assigned charge key at any compatible charger, on the Spirii network or a roaming partner's.
The platform captures the CDR: session start and end, energy consumed, price, and the charge key that authenticated it.
Through the billing period, every session for that fleet or eMSP accumulates under a single billing document per country and currency.
At the end of the period, Spirii sends one invoice covering every session by every driver, with a specification attachment detailing each one.
Spirii pays the revenue on to the CPOs whose chargers were used, and settles with any roaming partners involved.
```mermaid theme={null}
flowchart TD
D("Drivers tap charge keys") --> N("Spirii network and roaming partners")
N -->|"CDRs"| S("Billing engine")
S -->|"one monthly invoice"| F("Fleet or eMSP")
S -->|"self-billing payout"| C("CPOs")
S -->|"settlement"| R("Roaming partners")
```
## What the invoice covers
Every session authenticated with a charge key issued under that billing customer, whether it ran on a public or workplace charger on the Spirii network, or on a partner network reached over Hubject or a direct OCPI connection.
Because the consumption is invoiced afterwards rather than paid at the charger, the monthly invoice is the VAT document. Individual sessions produce a statement instead of a receipt. See [Receipts](/capabilities/compliance/receipts).
## Billing service levels
The billing service level set on the operator decides whether Spirii invoices the end customer or hands you the data to invoice them yourself.
| Service level | What Spirii does | Choose it when |
| - | - | - |
| **Full Service** | Invoices the fleet company or driver directly, and reports the VAT as the invoicing party | You want the billing relationship off your books entirely |
| **Invoice Data Service** | Produces aggregated billing data for you to invoice from, and settles roaming sessions | You hold the customer relationship and issue the invoices under your own brand |
| **No service** | Records the session and settles roaming sessions, nothing further | You bill from your own systems and need Spirii only for the session data |
## What each side sees
**Fleet managers** see every session their drivers ran in Spirii Connect, with live session status and historical CDR exports.
**Drivers** tap, charge, and leave. The company's monthly invoice handles the rest, whether they charged at the office, on a public charger, or at home with [home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) configured.
## Dependencies & limitations
* **Autocharge charge keys do not work over roaming.** A vehicle key is read by the charger itself, so it only works on chargers managed by Spirii's platform — a driver relying on Autocharge needs an RFID or virtual charge key as well to charge on partner networks. See [Charge keys](/components/access/charge-keys).
* **Physical charge keys need a reader.** Usually that's the charge box's own RFID reader. On a charge box without one, a [Spirii POS terminal](/capabilities/payments/in-person-payments) can read the charge key instead, and the session is billed exactly as if it had been tapped at the charger. Virtual charge keys need no reader.
* **Charge key sessions produce a statement, not a receipt.** The statement carries no VAT details, because the monthly invoice is the VAT document for that consumption.
* **CPO payout follows the month.** Revenue from charge key sessions reaches the CPO the month after the sessions ran, in the same cycle as app and terminal revenue.
## Related
How charge keys are issued, typed, and managed.
How the billing engine turns CDRs into invoices and payouts.
How sessions on other networks are invoiced and settled.
Automate reimbursement for employees charging at home.
# Home charging reimbursement
Source: https://docs.spirii.com/capabilities/billing-payouts/home-charging-reimbursement
Paying employees back for the electricity their company car uses at home, without anyone filing a claim.
Home charging reimbursement pays employees back for the electricity their company car uses at home. Spirii attributes each session to an employee, prices it, and produces a monthly expense report. The money goes out through the fleet company's payroll, or through a licensed payment service provider (PSP).
## Overview
A home charging session is an expense claim the employee never has to file. The work is in producing that claim: knowing which sessions on a private charger belong to the company car, what they were worth, and which ones need correcting before anyone is paid. Spirii handles the attribution and the pricing, and gives fleet managers a view to check and adjust before they approve.
Paying employees directly for energy can count as money remittance, which is a regulated activity. That is why disbursement through Spirii runs via Paytech, a licensed PSP. Running reimbursement through payroll instead is often the better route, and it keeps every payment to an employee in one place.
## How it works
### Setup
The fleet company and their CPO agree the terms for home charging reimbursement.
Each employee's home charger is connected to the platform, and they are issued a charge key.
Each employee's home charger location gets a Company Car agreement, which links it to the fleet company and holds the terms that employee is reimbursed on.
### The monthly cycle
Each session is attributed to the employee through their charge key or, where the location reimburses all sessions, through the location itself.
The billing engine collects each employee's home charging sessions for the period.
A Fleet Expense Report shows each employee's total consumption and the amount owed to them, and goes to the fleet manager for review.
With any corrections applied first, such as a session that went unattributed.
### Paying the employees
The fleet company takes the approved report and adds the amounts to payroll. Employees receive their individual expense reports directly, so they know what to expect in their next pay run.
The fleet company transfers the total to a dedicated settlement account held by the PSP. Once the funds land, the PSP disburses each employee's amount to their registered IBAN, and each employee receives an individual expense report confirming it.
## The Company Car agreement
A Company Car agreement is a financial agreement with its type set to **Company car**. You create it, or change an existing agreement's type, when [setting up the employee's home location](/capabilities/connection/location-configuration) in Spirii Connect. Everything about how that employee is reimbursed sits on it.
| Setting | What it does |
| - | - |
| Company car employee | The customer the reimbursement is paid to |
| Reimbursement rate | The price per kWh the employee is paid, used where the location has no [reimbursement rate](#reimbursement-rates) of its own |
| Company car management fee | An extra fee the CPO charges the employer, applying to company car home charging only |
| Remove tax from reimbursement | Reimburses the employee at a rate excluding tax |
## Reimbursement rates
The rate an employee is paid per kWh is set on their home location: on the location's **Rates** tab in Connect, or through the [Reimbursement rates API](/api-reference/reimbursement-rates/get-reimbursement-rates-for-one-or-more-locations). A rate created in one appears in the other. Where a location has a rate, it is used instead of the rate on the Company Car agreement, and a location without one keeps using the agreement rate.
Each rate has a start date, an optional end date, a currency, and a price per kWh, so changing what you pay applies from the date you set rather than rewriting earlier months. A rate whose period conflicts with another rate on the same location is rejected when you save it. Supporting evidence, such as an electricity bill, is attached to the rate itself, where it can back the rate in a validation or a tax audit.
Once a rate has been used in an expense report, it locks. An approved report cannot change because someone edited the rate behind it.
## What fleet managers see
Fleet managers get a full view of home charging activity in Connect:
* Every session per employee, with energy consumed and the reimbursement amount
* The reimbursement rate applied to each session, in its CDR details
* The rates set on each employee's home location
* The monthly Fleet Expense Report, before and after approval
* The status of individual reimbursements
Sessions can also be added to or removed from a report before approval — useful where a session went unattributed because it was not authenticated.
### Getting the report
A Fleet Expense Report reaches you by whichever route fits your payroll or expense process.
* **Email.** Sent as a PDF to the invoice email set on the fleet customer.
* **Download in Connect.** The same report as a PDF, or as a CSV for a payroll or expense tool.
* **Public API.** Retrieve reports programmatically with the [Reimbursement expenses API](/api-reference/reimbursement-expenses/list-expense-reports).
## What employees see
Employees charge at home and receive a monthly expense report confirming the amount reimbursed. No manual claims, no receipts to keep. Where the location reimburses all sessions, they don't need to start a session with their charge key either.
## Dependencies & limitations
* **Sessions need a charge key, unless the location reimburses all sessions.** By default, only sessions started with a charge key are reimbursed, so a forgotten tap, or a charger in free-vend mode, leaves sessions out of the expense report. Turning on *Reimburse all sessions to the location owner*, in the Reimbursement section when you create or edit the location in Connect, reimburses every session recorded at the location instead. It's off by default.
* **Reimbursing all sessions covers everyone who charges there.** The setting applies to the whole location, with no per-driver or per-connector control, so a session charged by someone else is reimbursed to the location owner too. Use it where one driver charges at the location, and keep reimbursement on charge key sessions where more than one does.
* **The location owner must be the employee.** Not the fleet company and not the CPO. Setting the company as owner because it bought the hardware is the common mistake, and it stops sessions being attributed.
* **The location needs a Company Car agreement.** Without one attached in Connect, its CDRs are not eligible for reimbursement.
* **A rate locks once it is used.** After an expense report references a rate, that rate is fixed. Correcting a past month means working with the report, not the rate.
* **Rates are a flat price per kWh.** Variable contracts such as spot-price tariffs, day and night pricing, and regulated rates aren't supported. A rate must be above 0 and no higher than 10 per kWh, with at most four decimals, and the maximum is the same in every currency.
* **Rates are deleted through the API.** Connect adds and edits rates but doesn't delete them. Delete an unlocked rate with the [Reimbursement rates API](/api-reference/reimbursement-rates/delete-a-reimbursement-rate-and-its-attached-documents).
* **Spirii-disbursed payouts wait on KYC.** Where the PSP pays employees, expense reports still generate before the fleet company's KYC completes, but no money moves until it does.
## Related
Configure operators, employees, and chargers for reimbursement.
The wider picture for company cars across home, workplace, and public charging.
How public and workplace charging is billed to the fleet company.
Retrieve expense reports and expenses programmatically.
# Understanding your payout
Source: https://docs.spirii.com/capabilities/billing-payouts/payouts
How to read your monthly self-billing invoice and reconcile it with the specification file.
Each month, Spirii issues a self-billing invoice covering the charging revenue it collected on your behalf during the billing period. Alongside it comes a specification file listing every CDR, included and excluded alike, so you can verify the payout in full.
## What a self-billing invoice is
A self-billing invoice is created by Spirii on your behalf. Instead of you invoicing Spirii for the sessions it collected on, Spirii tracks the consumption, calculates the revenue, generates the invoice, and processes the payout from validated session data.
The invoice is legally equivalent to one you would send yourself, so you do not need to issue a separate invoice to Spirii.
Each supplier receives one document per country and currency, and the invoice carries a single consolidated line for total consumption in that period and currency — a deliberate simplification that keeps it clean and auditable.
## What the payout covers
Your payout covers revenue Spirii collected for sessions on your chargers during the billing period.
Self-billing is based on when charging sessions **end**, not when they start. A session that completes late in a period, or arrives late because a charger was offline, lands in the earliest billing period still open.
App, terminal, and charge key revenue pays out the following month. Roaming is the exception: it pays in the same month Spirii invoices the roaming partner, so a given month's income can reach you in two parts.
## The specification file
Alongside the invoice PDF comes a specification file containing all CDRs for the billing period. It covers both included and excluded sessions, so you can see what was counted and what was not.
Key columns:
| Column | What it tells you |
| - | - |
| `isIncluded` | `true` if the CDR is counted in the payout, `false` if excluded |
| `priceExVat` | The session price excluding VAT. This is the field to sum when reconciling |
| `excludedReason` | Why the CDR was left out, where `isIncluded` is `false` |
Filtering on `isIncluded = true` also gives you a basis for revenue reports by location, country, city, or customer.
## Reconciling the invoice
To verify that the self-billing invoice matches the specification file:
Filter the rows where `isIncluded = true`.
Add up `priceExVat` across those rows.
The total should match the invoice amount. The line total carries no VAT, because these invoices use reverse charge, where the recipient rather than the supplier accounts for the VAT.
Export CDRs from Spirii Connect for the same billing period and compare session counts and total kWh. Small differences are normal where sessions ended just after the period closed and were held for the next cycle.
For questions about specific entries in the specification file, contact [finance@spirii.com](mailto:finance@spirii.com).
## Exclusion reasons
The `excludedReason` column explains why a CDR was not included in the payout. The possible values are:
| Exclusion reason | What it means |
| - | - |
| `Free Charging` | Home charging, voucher usage, or Fleet Depot sessions at no charge |
| `Chargebox open without authentication` | The charger did not rely on the charge point management system for session validation. The session shows as "Unauthorized", "NoTag", "NoUID", or "Auth. Disabled" |
| `Consumed energy is < 0.2 kWh` | A zero-kWh session, caused by a communication or equipment error between the vehicle and the charger |
| `Payment method is payment terminal and Spirii is not the merchant` | The CPO uses their own acquiring agreement under PAAS, so funds are paid directly by the CPO's PSP |
| `Invalid meter values received from the charger` | The charger is not OCPP-compliant, or sent inconsistent data such as negative or unusually large consumption figures |
| `Session duration is more than 7 days` | Revenue cannot be guaranteed on a payment reservation held that long |
| `Your Fleet Charging` | Operator or fleet customer sessions where Spirii billing is not used and revenue is collected separately |
| `Authorised with system tag` | The charge key is marked for installation or maintenance use, and is treated as free regardless of any tariff assigned to it |
| `Peer-to-peer settlement` | The CPO settles directly with a third-party eMSP, outside Spirii's automatic revenue system |
## Fees
The payout is net of Spirii's platform and payment fees, but the fees are not deducted line by line on the self-billing invoice. They arrive on a separate platform invoice. Neither document is the full financial picture for the period on its own; you need both.
## Related
Who collects, who invoices, and who pays out across every channel.
How payouts are distributed when site owners or subsidiaries are involved.
The session and CDR records the specification file is built from.
How CDRs are processed into invoices and payouts.
# Revenue sharing & automated payouts
Source: https://docs.spirii.com/capabilities/billing-payouts/revenue-sharing
Paying a site owner their share of the charging revenue without moving money yourself.
Spirii collects charging revenue and pays it out each month. Where a location belongs to someone else, that payout can be split, so the site owner is paid their share directly rather than waiting on a transfer from you.
## Overview
Most operators take a single monthly payout covering everything Spirii collected on their chargers. See [Understanding your payout](/capabilities/billing-payouts/payouts) for how that invoice is built and reconciled.
Revenue sharing changes who receives it. If you run chargers on behalf of other businesses, whether landlords, retailers, or hotel chains, Spirii issues each party its own self-billing invoice and pays each one separately. The same mechanism covers a group structure, where a CPO and its national subsidiaries are separate legal entities that each need their own invoice.
## How the split works
The revenue split lives on a **financial agreement**, which governs the fees and rates for sessions at a location. Create one while setting the location up, or link an existing agreement to a location afterwards. The agreement holds the share that goes to the customer who owns the site. See [Location configuration](/capabilities/connection/location-configuration).
After each billing period, the site owner receives a self-billing invoice for their share, and you receive a separate one for the remainder.
Payments go to each registered bank account independently. There are no transfers for you to make.
```mermaid theme={null}
flowchart TD
D("Driver") -->|"pays"| S("Spirii")
S -->|"CPO share"| C("CPO")
S -->|"site owner share"| CSO("Site owner")
C -.->|"optional onward split"| SUB("Subsidiary")
```
## Setting the share
The split is expressed one of two ways, and they behave differently.
| Method | What it means | Use it when |
| - | - | - |
| Percentage | A percentage of the tariff set in Spirii Connect | The site owner's return should track what you charge drivers, including any price changes |
| Rate per kWh | A fixed net rate on the energy delivered | The site owner wants a predictable amount per kWh regardless of what the tariff does |
## Dependencies & limitations
* **The site owner has to exist as a billing entity first.** They need a billing entity in the Business Portal and their bank details registered with Spirii before a split can pay out. See [Set up revenue sharing](/guides/revenue-sharing-setup).
* **Spirii executes the split — it does not mediate it.** The commercial agreement with the site owner is yours. Spirii pays out exactly as configured and stays out of any dispute over what the share should have been.
* **Terminal revenue under PAAS is not in the payout.** Where you hold your own acquiring agreement, funds reach you directly from your PSP and never enter the pool that gets split.
* **Bank detail changes go through Spirii.** If the site owner's account changes, it has to be updated before the next billing cycle closes, or that period's payout follows the old details.
## Related
Configure a site owner split, step by step.
How to read a self-billing invoice and reconcile it against Connect.
Who collects, who invoices, and who pays out across every channel.
# Roaming settlement
Source: https://docs.spirii.com/capabilities/billing-payouts/roaming-settlement
How Spirii invoices and settles between networks when drivers charge across operators.
Roaming earns you revenue when drivers from other networks use your chargers, and costs you money when your drivers use theirs. Spirii sits between both: invoicing roaming partners for inbound sessions, and receiving and reconciling their invoices for outbound ones.
## Two directions of roaming
A driver from another network charges on your charger. You earn revenue. Spirii invoices the driver's eMSP or roaming hub and pays you.
Your driver charges on another network. You owe that network. Spirii receives their invoice and bills you on a consolidated basis.
## Inbound roaming: getting paid
Over a roaming hub or a direct connection, depending on how that partner is reached.
Spirii generates the CDR and returns it to the driver's eMSP over the same protocol.
Priced on the roaming tariff set for that location. You enter that tariff gross, but the eMSP is billed the net amount, and net is what the session is worth to you. See [Roaming pricing](/capabilities/pricing/pricing-options-and-logic#roaming-pricing) for how the tariff is chosen and when a change takes effect.
Funds are collected from the roaming partner, and your share reaches you on a self-billing invoice.
You can also settle directly with a roaming eMSP under a peer-to-peer agreement instead of going through Spirii. Your account manager can set that up, and it changes where the money arrives: peer-to-peer sessions are settled between you and that eMSP, not through your Spirii payout.
## Outbound roaming: consolidated billing
At the rate that network has pre-agreed with Spirii.
At the tariff configured for outbound roaming, which is the price your driver or their fleet company pays.
A single consolidated invoice covering all outbound roaming by your drivers, rather than a separate invoice from every network they stopped at.
## Roaming networks
Spirii connects to the roaming ecosystem through:
| Connection type | Examples |
| - | - |
| **Roaming hubs** | Hubject, Gireve, e-clearing.net |
| **Direct connection** | Bilateral OCPI connections with specific operators |
Enabling roaming on a location or a charge key reaches every network Spirii connects to. There is no per-hub configuration to repeat, and no separate agreement to negotiate with each one.
## Dependencies & limitations
* **Roaming pays on a different cycle to everything else.** Roaming revenue reaches you in the same month Spirii invoices the roaming partner, while app, terminal, and charge key revenue pays the following month — so a single month's income arrives in two parts.
* **Peer-to-peer sessions are not in your Spirii payout.** Where you settle directly with an eMSP, those sessions are excluded from the self-billing invoice and appear in the specification file marked as such. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **Roaming sessions produce a statement, not a receipt.** The statement carries no VAT details, because the invoice between networks is the VAT document for that consumption. See [Receipts](/capabilities/compliance/receipts).
* **Autocharge does not work over roaming.** A vehicle charge key is read by the charger itself, so it only works on chargers managed by Spirii's platform; your drivers need an RFID or virtual charge key to charge on partner networks. See [Charge keys](/components/access/charge-keys).
## Related
Publish chargers and connect charge keys across roaming networks.
Which networks your drivers can reach, and how to filter them.
How your drivers' sessions, roaming included, land on one monthly invoice.
The records that drive roaming invoicing and settlement.
# Change history
Source: https://docs.spirii.com/capabilities/compliance/change-history
Trace an edit back to the person who made it.
Spirii Connect records the edits made to your data: who made them, the values before and after, and when.
## Overview
Why a tariff changed, who removed a location from a voucher group, when a price was last edited: those questions come up after the fact, and Connect logs the changes as they happen.
Two surfaces reach that record.
A tab in Connect on locations, voucher groups, and tariffs, showing field-level edits in place.
The same records, filterable by user, address, record type, event, and date range.
## Change history in Connect
Locations, voucher groups, and tariffs each carry a **Change history log** tab, listing the edits made to that record.
### What a row shows
| Column | What it shows | Example |
| - | - | - |
| Timestamp | When the change was made | `14 Jul 2026, 09:12` |
| Field | Which field changed | `Base price` |
| User | Who made the change | `lena.weber@example.com` |
| Previous value | What the field held before | `0.42` |
| New value | What it holds now | `0.45` |
Changes are attributed to the signed-in user who made them. Where an operator is impersonating a customer, the row names the operator's own user rather than the customer.
The tab is scoped to the record in front of you, so a location's history covers the location's own fields. Record creation, deletion, and association events are reachable through the API rather than here.
## The audit log API
[`GET /v2/audit-logs`](/api-reference/audit-logs/fetches-a-list-of-audit-logs) returns the recorded changes, including the event types and record types the Connect view does not surface.
### What a change record contains
| Field | What it records |
| - | - |
| User | The email address and ID of the user who made the change |
| IP address | The address the change was made from |
| Endpoint | The endpoint that was called |
| Record type | What kind of record changed, such as a location or a voucher group |
| Record ID | Which record changed |
| Event | What happened to it |
| Before and after | The field values as they were, and as they became |
| Operator and customer | The account the acting user belongs to |
| Timestamp | When the change was recorded, in UTC |
### Event types
| Event | Meaning |
| - | - |
| `created` | A record was created. The before values are empty |
| `updated` | One or more fields changed |
| `deleted` | A record was deleted. The after values are empty |
| `associated` | A record was linked to another, such as a location added to a voucher group |
| `disassociated` | A link between two records was removed |
On an association event, the record also names the type of record on the other end of the link.
### Filtering
Filters cover the questions an investigation usually starts from:
* **Who** — by user email or user ID
* **Where from** — by IP address
* **What** — by record type, record ID, or event type
* **When** — a date range, with cursor pagination for large result sets
Each entry carries the before and after values, so the API answers what changed rather than only that something did.
## What is covered
Change history is the record of edits made in Connect. Each entry accounts for one change, with the user, the values, and the timestamp behind it.
Its scope is those edits. Updates written programmatically through the public API are separate, so where changes are automated your own systems hold the record of them.
Charger-level activity is separate too. Actions and configuration changes on a charge box, and the settings a driver adjusts on their own residential charger, are not change-history events. Read a record's entries as the account of its Connect activity.
## Dependencies & limitations
* **Change history covers edits made in Connect.** Updates through the public API are separate.
* **The Connect view covers three record types.** Locations, voucher groups, and tariffs. The API reaches the rest.
* **The Connect view shows edits only.** Record creation, deletion, and association events are in the API rather than the tab.
* **Charger-level activity is separate.** Actions and configuration changes on a charge box are not change-history events.
* **No retention window applies.** Change records are not aged out on a schedule, so history reaches back as far as the record itself.
## Related
To see who is able to make changes in the first place, start with the roles you have granted.
The roles that decide who can change what.
How changes are attributed when acting in a customer's context.
Which records a user can reach, and whose driver details they can see.
Endpoint reference, parameters, and response schema.
# Data separation
Source: https://docs.spirii.com/capabilities/compliance/data-separation
How the platform keeps each partner's data, and each driver's details, separate.
Every record in the platform belongs to an operator and a customer, and that pairing decides who can reach it. A user's role then decides what they can do with what they reach.
## Overview
Spirii Connect is a shared platform holding many operators' networks, their customers' sites, and their drivers' accounts. Keeping those apart is structural rather than configured, and it works on three boundaries:
| Boundary | What it separates | Set by |
| - | - | - |
| Hierarchy | Which records a user can reach at all | The customer their user belongs to, and its position beneath an operator |
| Role | What they can do with those records | One of eight roles |
| App ownership | Which drivers' personal details are visible | The app the driver signed up in |
This page describes how the three work together. Each is configured on its own page, linked below.
## The hierarchy boundary
Every location, tariff, voucher, charge key, and charge box is tied to a customer, and every customer sits somewhere beneath an operator. A Connect user reaches the records of their own customer and of any customers beneath it, and nothing else.
That means separation follows the shape of your business rather than a permissions list somebody maintains. A site owner sees their own sites. A regional entity sees the entities under it. An operator sees everything in its own tree and nothing in anyone else's. There is no way to grant a user access to data outside that boundary.
See [the customer hierarchy](/capabilities/account/customer-management#the-customer-hierarchy) for how it is structured, and [Team Access](/capabilities/account/user-management) for scoping a user within it.
## The role boundary
Reaching a record and being able to change it are separate questions. A user's role sets what they can do across everything they can see, from viewing only through to administering the platform.
Personal data follows the same role boundary as everything else, with two exceptions: the **Installer** and **Depot Manager** roles do not reach it. An installer commissioning a charge box on a customer's site works with the location and the hardware, not with the drivers who will use it.
See [Roles](/capabilities/account/roles) for the eight roles and what each can do.
## The app user boundary
A driver's personal details sit behind a boundary of their own, and it is set by the driver rather than by you.
When someone signs up in an app, they accept that app owner's terms and privacy notice. That agreement is with one specific party, so that party is who can see them. Only the operator whose app they signed up in reaches the record. Where an onboarding flow created the account, the customer behind that flow can reach it too, because the driver accepted their terms during the order.
The consent and the technical boundary are the same boundary. A driver who never agreed to anything with you does not appear in your Connect, even when they charge on your chargers — their sessions arrive attributed to an anonymised identifier instead.
See [App users](/components/access/app-users) for what the record holds and who can manage it.
## Spirii's own access
The boundaries above separate partners from one another. Spirii sits outside them: a Spirii administrator can reach all platform data, which is what allows support to investigate a fault, reconnect a charge key to a driver, or recover something that was removed.
Work a Spirii administrator does in Connect is written to the change history against their own user, the same as anyone else's.
## When a charge key crosses a boundary
The boundaries can also disagree. A charge key can be associated with an app user, and the two do not have to belong to the same partner: `Rheinstrom GmbH` issues a charge key, and the driver holding it signed up in an app belonging to `Acme Inc.`
```mermaid theme={null}
flowchart LR
O1("Rheinstrom GmbH\nowns the charge key") --> T("Charge key")
T -.->|"association"| AU("App user")
O2("Acme Inc.\nowns the app") --> AU
```
The charge key itself holds no personal data, so the operator who owns it sees the charge key in full: its label, activation status, roaming status, and comment, and the fact that an app user is associated with it. What they cannot see is who that driver is.
In the charge keys table, the app user column reads **anonymised**. On the charge key's own page, the app user card is covered by an overlay reading **blocked due to Spirii privacy policy**, with a tooltip explaining that the app user bound to this charge key is not associated with your account.
The boundary runs one way. An operator who owns the app user, but not the charge key, gets an error when they try to open the charge key: it is not associated with their account.
Either side can remove the association. The charge key's owner can take the driver off it from Connect, and so can the app user's owner — or the driver themselves, by removing the charge key in the app.
The charge key's owner cannot restore an association once it is removed, because reconnecting it needs access to the app user record they cannot see. Spirii support can reconnect them, so treat removing it as a one-way action on your side.
## Dependencies & limitations
* **Access cannot be granted outside the hierarchy.** A user reaches their own customer and those beneath it. There is no exception to configure.
* **Installer and Depot Manager roles do not reach personal data.** Every other role does, within its own data boundary.
* **App user records are visible to the app's owner.** A customer associated through an onboarding flow can reach them too. Nobody else can.
* **Removing a charge key's app user association is not reversible by the charge key's owner.** Either side can remove it; restoring it requires Spirii support.
## Related
To change who reaches what, start with the user's customer and role.
The hierarchy every record is tied to, and the boundary it creates.
Scoping a user to a customer, and the eight roles.
The driver record, and who is permitted to see it.
Charge keys, and how they associate with a driver.
The record of what was changed in Connect, and by whom.
# Receipts
Source: https://docs.spirii.com/capabilities/compliance/receipts
VAT-compliant receipts for every session, produced by the platform.
Every completed session produces a document for the driver. Whether that is a receipt or a statement, and whose VAT appears on it, follows from how the session was paid for.
## Overview
Charging is a sale, and a sale needs a document. Since the EU's Alternative Fuels Infrastructure Regulation (AFIR) put payment terminals on public chargers, that document has to reach drivers who never opened an app and never signed up for anything.
Getting that right is fiddly. What belongs on the document depends on who took the payment, which country the session happened in, and whether it will be invoiced later. The platform works that out for each session, generates the document, and makes it reachable without an account. None of that logic is yours to build or maintain.
## Receipts and statements
Which document a driver gets follows who took the payment: Spirii through an app, a point-of-sale (POS) terminal at the charger, or an invoice raised afterwards.
| Paid with | Document | VAT shown | Named as the service provider |
| - | - | - | - |
| Spirii Go or a branded app | Receipt | Spirii's VAT number for the country the session took place in, or Spirii's Danish number where there is no local one | Spirii |
| A card or phone at a Spirii POS terminal | Receipt | The merchant's name, address, and VAT number | The merchant, which can be you or Spirii |
| A third-party POS terminal | Statement | None | None |
| Roaming on your chargers | Statement | None | None |
| A charge key, at the charger or a Spirii POS terminal | Statement | None | None |
One principle sits behind the table. Where the driver paid at the moment of charging, the document is a receipt and carries the VAT of whoever took that payment. Where the session is invoiced afterwards, as roaming and charge key consumption are, the invoice is the VAT document and the statement carries none.
For card and phone payments on a Spirii POS terminal, the merchant details come from the terminal's own merchant record, so the receipt names whoever actually took the payment. See [In-person payments](/capabilities/payments/in-person-payments) for how that is set up.
## What a receipt contains
| Line | What it shows |
| - | - |
| Session | The date, the duration, and the energy consumed |
| Price | The tariff applied, and the final price |
| VAT | The rate, the amount, and the details of whoever took the payment |
| Location | The site's name and address |
| Your own text | Any custom receipt text set on the customer that owns the location |
## Finding a receipt
**In the app.** App users get their charging history and receipts in Spirii Go or a branded app.
**At a link.** Every session has its own receipt page, reachable without an account. This is what makes contactless charging work: a QR code on the terminal screen when the session ends, or a link sent by email or text.
You can retrieve any session's link yourself. Both the **Ongoing sessions** and **Charge records** tables in Spirii Connect carry a detailed receipt button beside each row's total price, available to the roles that can view session data. That is how you get a receipt to a driver who has lost theirs.
**On an invoice.** Charge key and roaming consumption is invoiced, and that invoice is the document for VAT reporting.
A receipt link is not behind a login, because an anonymous driver has no account to sign in to. Treat the link as you would any other link that exposes a single transaction.
## Custom receipt text
You can add your own text to the bottom of a receipt. You set it on the **customer**, and it appears on receipts for sessions at every location that customer owns.
Three things it gets used for:
* **Compliance wording.** Some public bodies require specific language on receipts, which is what the field was built for.
* **Support information.** A number or address for a driver who needs help with a charge.
* **An offer.** A free coffee at the site shop, or a code to use elsewhere.
The field takes up to 200 characters, which is roughly two short sentences. `Questions about this charge? Call Rheinstrom support on +49 89 1234 5678.` uses 73 of them. Only an Operator can set the text.
Because the text belongs to a customer rather than to a location, an operator working across several markets sets up a customer per market or business unit and gives each one its own wording. That is also how you handle language: the text is stored as you write it, so a French entity's receipts carry French text.
## Dependencies & limitations
* **Custom text appears on receipts, not statements.** Sessions paid by charge key, over roaming, or at a third-party terminal produce a statement, which does not carry it.
* **One text per customer.** There is a single field, so different wording for different markets means separate customers.
* **200 characters.** Enough for a compliance line or a support contact, not for a paragraph.
* **Third-party terminal sessions carry no VAT details.** That provider handles the payment, so the statement records the session without VAT information.
* **A receipt link is not authenticated.** Anyone holding the link can see that session's receipt.
## Related
The text is set on the customer, so that is where to start.
Where custom receipt text is set, alongside a customer's other details.
Terminals, merchants, and what appears on a receipt taken at the charger.
Payments taken in Spirii Go or a branded app, and the receipts they produce.
How invoiced consumption is billed, and where VAT is reported for it.
# Charger activation
Source: https://docs.spirii.com/capabilities/connection/charger-activation
How a physical charger is provisioned, connected, and configured on the Spirii platform.
Connecting a charger brings a physical unit onto the Spirii platform: you create a charge box, point the charger's OCPP backend at Spirii, and it comes online and configures itself on the first connection.
## Overview
Every charger runs on the platform as a **charge box**: the object representing the physical unit, holding the EVSEs and connectors that deliver power. Bringing one online is a two-part handshake. You create the charge box first, as a placeholder on a location; the physical charger connects to it afterwards, once your installer points it at Spirii. The platform links the two by identity, so the charger you configure on site and the charge box you created in the platform are the same unit.
You can do the platform side in **Spirii Connect**, the admin web app, or through the **Spirii API** (the same connection, two interfaces). Either way the shape is the same: a charge box sits **Pending** until the charger reaches it, then goes **Online** and self-populates.
## How it works
You create the charge box against a location and give it the charger's identity, the **charge box ID (CBID)**. That reserves a placeholder with a status of **Pending**: the platform knows a charger is coming but hasn't heard from it yet.
Your installer then configures the physical charger to use Spirii as its OCPP backend, at the secure endpoint `wss://ocpp.spirii.com`, presenting the same CBID as its OCPP identity. Matching identities is what lets the platform bind the connection to the charge box you created; a mismatch leaves the box stranded as Pending. Reaching the endpoint requires TLS 1.2, the AWS Root CA certificate, and the security profile information.
On the charger's first connection it sends a `BootNotification` (the opening message of the OCPP handshake) and the platform reads back the unit's details and provisions everything beneath it automatically. There's no manual activation step: once the `BootNotification` arrives, the box comes **Online** and is ready to charge.
### Example
You add a charge box at Munich DC Hub for a new Alpitronic HYC\_400, selecting its model and entering the CBID `DE*SPI*E00012345`. The box is created **Pending**. Your installer points the charger at `wss://ocpp.spirii.com` using that identity, and within five to ten minutes it sends its first `BootNotification`. The platform records the vendor, the model (`HYC_400`), the firmware (`hyc_2.4.0`), and the EVSEs and connectors on the unit. Because the EVSE IDs are derived from the CBID, the unit's connector comes up as `DE*SPI*E00012345*1`. The box is now Online.
If a charger hasn't connected within about ten minutes, it usually needs a reboot to retry, or its OCPP configuration doesn't match the charge box, most often the identity.
## Connect or the API
Both interfaces do the same job. Choose by how many chargers you're onboarding and whether the work is manual or programmatic.
| Interface | Use it when | Where to go |
| - | - | - |
| Connect | You're onboarding a charger by hand, or managing a site day to day | [Quick start for CPOs](/guides/cpo-quickstart) walks the full flow |
| Spirii API | You're onboarding at scale, or building charger provisioning into your own systems | [`POST /chargeboxes`](/api-reference/chargeboxes-v2/creates-a-new-charge-box) creates the box; a box stays `Pending` until it connects, exactly as in Connect |
A charge box created over the API behaves exactly as one created in Connect: it's a placeholder in the same `Pending` state, waiting on the same `BootNotification`.
## Configuration
A charge box carries the settings that govern how the unit runs: its OCPP configuration, connector setup, and model-specific controls. When a charger first connects, the platform reads back the manufacturer's defaults for its model and firmware, so a newly connected box already holds a working configuration you can then adjust.
Rather than tune every value by hand, you can **import a full configuration from another charger** of the same model and firmware version. This is the fastest way to bring a second identical unit up to your preferred setup, and it's worth standardising on when you run several of the same model across a site.
Some charger models store their CBID inside the configuration, often in a field whose name contains `identity`. An import overwrites every value, so after importing, set that field back to the new charger's own CBID before saving. Leaving the source charger's identity in place causes both units to connect as the same charge box.
## Set up
Before you connect a charger you need three things in place:
Connection and configuration are supported on the models Spirii has tested; check whether yours is covered before you commit hardware (see Dependencies below).
The charge box is created against a [location](/components/charging/locations), which gives it its address, access, and pricing.
Operator access in Connect, or API credentials. See [Authentication](/developers/authentication) for the API path.
Physical installation stays with your installer and the manufacturer's manual: mount the unit, give it power and a network connection, and point its OCPP backend at Spirii. From there, the platform side is the flow above; the [Quick start for CPOs](/guides/cpo-quickstart) walks it end to end.
## Dependencies & limitations
* **Validated hardware only.** Chargers connect and configure reliably on models Spirii has validated. See [Charger validation](/capabilities/connection/charger-validation) for what's tested and where to check a model. Model validation also records whether a model supports firmware management and Plug & Charge, so hardware capabilities are known before onboarding rather than discovered after.
* **OCPP 1.6J.** Chargers connect to the platform over OCPP 1.6J. The charger's OCPP identity must match the CBID on the charge box, or the connection won't bind.
* **Configuration import needs a matching charger.** You can only import a configuration from a charger of the same model and the same firmware version, because the available configuration keys differ across both.
* **Deleting or moving a charger.** Deletion is a soft delete, and a charge box can't be deleted while it has an active charging session. To move a charger to another location, delete it from the old one and recreate it at the new one; its history and charge detail records stay with the original location, and the recreated box starts fresh.
## Related
The object a charger runs as, and where its firmware, connectivity, and logs live.
The charging units provisioned automatically beneath a connected charge box.
The full walkthrough: customer, location, charge box, and first charge.
Create and manage charge boxes programmatically.
Bind a charger to a circuit to balance power across a site.
Act on a connected charger from the platform: reset, remote start and stop, unlock connector.
# Charger validation
Source: https://docs.spirii.com/capabilities/connection/charger-validation
Check that a charger model is supported before you commit hardware, and get a new model tested when you need one.
Charger validation is how Spirii tests a charger model on the platform: its core OCPP 1.6 integration, and separately, each advanced feature the model can support.
The public list of validated models, by manufacturer, model, firmware, and type.
## Overview
You can connect any OCPP 1.6-compliant charger to Spirii. Validation is what makes a model supported. Spirii's operations team has tested it on the platform, so the integration is one Spirii can guarantee.
A model is validated in two layers, and it can pass the first without the second:
* **Core integration.** The model connects and runs on the platform over OCPP 1.6. Every model on the supported list has passed this.
* **Feature validation.** Each advanced feature is validated separately. A model can be fully supported for charging with no features validated at all.
Check a model before you buy or install it. Finding out once the hardware is on site leaves you choosing between running without the features you planned on and waiting for the model to be validated.
## What's validated, and where to check
| Validation | Where to check |
| - | - |
| Core integration | The [supported chargers list](https://spirii.notion.site/Chargers-supported-in-Spirii-4ff0f9d78a914082874fb607fdaaae59), or [`GET /v2/chargeboxes/models`](/api-reference/chargeboxes-v2/fetches-a-list-of-supported-charge-box-models) |
| [Plug & Charge](/capabilities/access/plug-and-charge) | `plugAndChargeValidated` on the models API |
| [Firmware management](/capabilities/operation-monitoring/firmware-management) | `firmwareManagementValidated` on the models API |
| [Dynamic load management](/capabilities/energy-management/dynamic-load-management) | Your Spirii representative |
| [Scheduled charging](/capabilities/energy-management/scheduled-charging) | Your Spirii representative |
| [Grid balancing](/capabilities/energy-management/grid-balancing) | Your Spirii representative |
The list is the quickest way to look a model up. The API reads from the platform's own model records, so use it when you're checking from your own systems, and go by it if the two ever disagree. The list is maintained to match the API, but it's updated by hand, so a newly validated model can appear in the API first.
## How validation works
```mermaid theme={null}
flowchart TD
A("A partner, prospect, or manufacturer requests a model") --> B("Spirii prioritises it in the validation queue")
B --> C("Spirii obtains a test unit from the manufacturer")
C --> D("Spirii tests the core integration and advanced features")
D --> E{"Passes?"}
E -->|"Yes"| F("Added to the supported list")
E -->|"No"| G("The manufacturer provides a fix")
G --> D
```
Spirii's operations team runs validation on a test unit supplied by the manufacturer, and works with the manufacturer's team throughout. If a model needs changes, the fix comes from the manufacturer and the model is tested again.
Requests join a single queue that Spirii prioritises. A model that a partner or prospect needs for a real deployment usually comes ahead of one a manufacturer puts forward on its own.
### Firmware versions
Validation is for a model, tested on a specific firmware version, which the supported list records. For most purposes the model is what matters. The exception is energy management: a model validated in the past can fall out of compliance after a firmware update, so an earlier validation doesn't guarantee dynamic load management or scheduled charging on a newer version.
Spirii doesn't re-validate every model when a manufacturer releases new firmware. Where Spirii upgrades firmware on your behalf as a service, the new version is tested as part of that upgrade.
## Get a model validated
Ask your Spirii representative to put the model in the queue. Name the features you need as well as the model, since each feature is validated separately and core validation won't cover them.
For example, a fleet operator planning a depot around dynamic load management finds its preferred model on the supported list, validated for core integration only. It asks for DLM validation before ordering, because the model being on the list says nothing about how it handles DLM.
Manufacturers can also put a model forward to Spirii directly.
## Dependencies & limitations
* **Unvalidated models connect, without a guarantee.** Any OCPP 1.6-compliant charger can connect to the platform. On a model Spirii hasn't validated, Spirii can't guarantee the integration.
* **Feature results are only partly published.** The models API flags Plug & Charge and firmware management. Validation for dynamic load management, scheduled charging, and grid balancing is confirmed by your Spirii representative.
* **New firmware isn't validated automatically.** An earlier validation carries no guarantee for energy management features on a newer firmware version.
## Related
Once your model is confirmed, [Charger activation](/capabilities/connection/charger-activation) covers connecting it to the platform.
Create the charge box and bring a validated charger online.
The site-level capabilities that depend on feature validation.
Confirm every model in your fleet is validated before planning a migration.
List validated models and their Plug & Charge and firmware management flags.
# Location configuration
Source: https://docs.spirii.com/capabilities/connection/location-configuration
How you set up a charging site in Spirii Connect before adding chargers.
A location is the container a charging site attaches to: its chargers, tariff, and records all hang off it. Configuring one sets that container up: its details and place on the map, the tariff its chargers bill against, how it's published, and when it's open. Everything you add afterwards then has somewhere to live.
## Overview
Every charger runs on a location, so a location is the first thing you set up. It holds the site's address and map position, the [tariff](/components/commercial/tariffs) its chargers bill against, its publishing settings, opening hours, and the charge records that come off it. The [Locations component](/components/charging/locations) covers what a location is and how it fits the rest of the platform; this page is how you configure one.
You create and configure locations in Connect under **Locations**, or through the [locations API](/api-reference/locations-v2/creates-a-new-location). The shape is the same either way: set up the location's details, choose how it's published and when it's open, then add chargers. You can also run several locations at one physical site, commonly to split AC and DC chargers, or to give two groups of chargers different pricing or access.
## Setting up the location
Creating a location runs through a single flow in Connect, with the same fields available over the API.
A location belongs to a [**customer**](/capabilities/account/customer-management), the account it's operated under. Select an existing customer or create one in Connect as you go.
Give the location a **name** drivers will recognise, since it's what shows in charging apps, and pick a [**location type**](/components/charging/locations#location-types) from the list. Parking Lot suits most depots, and Public Road is a common type for public charging hubs. The type is for internal categorisation and isn't shown to drivers. Residential is a special case: it needs no tariff, and lets you choose whether the site owner sees the charger in their app.
Enter the **address**, and the platform places a **map pin** from the derived coordinates. Drag the pin if the chargers sit away from the address entrance, or if two locations share an address and their pins would overlap. Accurate coordinates matter: they're what drivers navigate to, and what roaming networks receive.
Every location needs a **tariff** to be operational: the price its chargers bill against, whether that's 0 EUR for your own fleet or a paid price for third parties. Tariffs are created on the Tariffs page and linked here; if you don't choose one, your operator default applies. See [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic) for how tariffs are built.
Optionally, select the **facilities** available on site, such as rest areas or amenities. These appear in apps and over roaming, helping drivers and fleet planners judge whether a site fits a route. A **financial agreement** can also be attached where one governs the fees and rates for sessions at the location; most own-fleet depots don't need one.
For an employee's home charger under [home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement), the location's **Reimbursement** section holds *Reimburse all sessions to the location owner*, which reimburses every session at the location to its owner rather than only charge key sessions. Once the location exists, its **Rates** tab holds the rate the employee is paid per kWh.
## Publishing settings
You configure publishing on an existing location: open it, select **Edit**, and change these settings there, rather than during the initial creation flow. Three settings control how a location is discovered and reached, and they're independent, so you combine them to fit the site.
Makes the location visible in charging apps and map services, and discoverable by drivers outside your organisation. Leave it off for a site meant only for your own users.
Keeps a location usable without listing it in Spirii-managed apps. A driver who arrives with a charge key that's valid in the Spirii network, or a payment card at a terminal, can still charge; the site is not shown for passive discovery. It's the setting for a site you want reachable but not advertised.
Lets drivers from other eMSPs charge using their own app or charge key, billed against a separate roaming tariff. See [Roaming connection](/capabilities/roaming/roaming-connection) for how roaming pricing and settlement work.
A private fleet depot typically stays unpublished; a commercial site is made public, and usually roaming-enabled to lift utilisation. What these settings don't govern is who is *allowed* to charge once they've found the site; that's the job of [Location access](/capabilities/access/location-access).
Making a location public brings regulatory obligations. Public charging in the EU falls under AFIR, the Alternative Fuels Infrastructure Regulation, which sets requirements around price transparency, ad-hoc payment, and consumer information. Responsibility for meeting them stays with you as the site's operator.
## Opening hours
Opening hours set when the site is open to all end-users. By default a location is open around the clock; instead you can define intervals per day, including more than one interval in a day, and drivers see these hours in the apps.
Outside opening hours, the site narrows to your own users: only a driver whose **charge key or voucher is tied to the location** can charge. So you might open the location to the public from 06:00 to 22:00 and keep it for your own fleet overnight, guaranteeing your drivers a free bay when they need it. How those charge key and voucher ties work is covered in [Location access](/capabilities/access/location-access).
## Adding chargers
With the location configured, you add chargers to it. Each charge box you connect sits on the location and inherits its tariff and publishing settings. [Charger activation](/capabilities/connection/charger-activation) covers how a charger is provisioned and comes online. While a new charger is being tested and not yet ready for drivers, you can give it a commissioning [temporary EVSE status](/capabilities/operation-monitoring/temporary-evse-status) so it doesn't appear available until you're ready.
## Dependencies & limitations
* **A tariff is required.** A location isn't operational until it has a tariff, even if that tariff is 0 EUR. Residential locations are the exception.
* **Create tariffs first.** Tariffs are made on the Tariffs page, not inside the location flow, so create the one you need before configuring the location.
* **Roaming has data requirements.** A location reaches roaming networks only when it's public, has a roaming tariff, carries accurate coordinates, and uses connector IDs in the required eMI3 format. See [Roaming connection](/capabilities/roaming/roaming-connection).
* **Publishing controls discovery, not permission.** These settings decide who can find and reach a site; who may actually charge is governed in [Location access](/capabilities/access/location-access).
## Related
What a location is, what it contains, and how it connects to the rest of the platform.
How the tariff a location bills against is built.
Publish a location to other networks, and how roaming is priced and settled.
Balance charging power across the chargers on a site.
Who can see and charge at a location, once it's configured.
Provision the chargers that run on the location.
# Spirii Go and branded apps
Source: https://docs.spirii.com/capabilities/driver-experience/spirii-go-and-branded-apps
Give drivers a way to find, start, and pay for a charge.
Spirii Go is Spirii's charging app for EV drivers. A branded app is the same app in your own identity, published under your own name in the app stores.
## Overview
Drivers need somewhere to find a charger, start a session, and pay for it. Spirii builds and maintains one app for that job, and offers it two ways.
Free for any driver to download, with no agreement or subscription. Point your drivers at it and they can charge on your network today.
The same app in your brand, on your own App Store and Google Play listings. Your drivers sign up with you, and the user base is yours.
The functionality is the same in both. What differs is whose brand drivers see, whose store listing they download from, and who holds the relationship with them afterwards.
## What drivers can do
A map with search and filtering, showing live availability, price, facilities, and opening hours for each location. Drivers can filter for fast DC charging or for specific operators, get directions to a charger, see when a location is typically busiest, and ask to be notified when an occupied charge point frees up.
They can also report a fault on a public charger from the app.
Start and stop a session from the app, or charge anonymously with no sign-up at all. Drivers save a card for future sessions and can pay by card, Apple Pay, Google Pay, or the local methods common in their market.
Where you run dynamic pricing, the app shows the price following the market rate. Where a driver holds a voucher, they enter its code to get the access or the price it grants. Drivers can also add a charge key to their account, so sessions on a physical or virtual charge key land against the same profile.
A full charging history with receipts, consumption tracking, and insight into charging behaviour over time. Drivers can add a VAT ID for business charging, and see the climate impact of charging at different times of day.
Drivers with a validated home charge box can control it from the app: see electricity spot prices ahead of time, schedule charging for the cheapest hours, and switch authentication on or off so the box either starts as soon as a car is plugged in or waits for confirmation.
They can also lock the cable to the unit, adjust the LED brightness, and cap the current in amps. Public sharing goes a step further: a driver sets a price on their own charger and makes it available to other drivers, and the energy those drivers pay for is paid out to them.
## Spirii Go or your own brand
Both routes put the same app in a driver's hands. The choice is about ownership.
| | Spirii Go | A branded app |
| - | - | - |
| Brand drivers see | Spirii | Yours |
| Store listing | Spirii's | Yours, on your own developer accounts |
| Driver signs up with | Spirii | You |
| Drivers you can manage | Those you onboard | Everyone who signs up |
| Support contact drivers see | Spirii | The details you provide |
| Cost | Free | Subscription per app |
| Available | Today | After a build and store release |
**Spirii Go suits an operator without an eMobility arm of its own.** There is nothing to build and nothing to maintain, so you can hand drivers a working app immediately, deliver vouchers and home charging through it, and get a network live without becoming an app publisher.
You are not locked out of the driver relationship either. Drivers who arrive through one of your onboarding flows are associated with a customer in your hierarchy, so you can manage them from Spirii Connect even though the app itself is Spirii's.
**A branded app suits an operator building its own eMobility business.** Drivers download your app, sign up with you, and accept your terms, which is what makes them yours: your app users, visible and manageable in your own Connect account.
### How releases reach a branded app
New features are released in Spirii Go first. They run there, in front of a large driver base, until their impact is understood, and then they reach the branded app portfolio. So a branded app trails Spirii Go by a release or two, and what arrives has been proven at scale rather than shipped untested.
## What you can brand
| Element | What you provide |
| - | - |
| App name | The name shown under the icon on a driver's home screen |
| App icon and splash screen | Your icons, at the sizes each store requires |
| Onboarding logo | Your logo, shown when a driver first opens the app |
| Colour palette | Your brand colours, including the colours of the map pins |
| Typography | Optionally a secondary font for headings |
| Support contact | The phone number and email address drivers reach you on, per country |
| Legal | Links to your own terms and conditions and privacy policy |
| Email sender | Emails to your drivers come from a subdomain for your app, falling back to Spirii's where one is not in place |
## Getting a branded app
**Prerequisites**
**Apple App Store account.** A developer account in your own name.
**Google Play account.** The same, for Android.
**Signing keys.** You provide them, and the app is published under your identity.
The listing, the reviews, and the relationship with each store therefore belong to you.
Beyond that, you supply the brand assets and details in the table above, then test the app and give final approval before it goes to the stores. Spirii handles the build, the store submissions, and the ongoing releases and maintenance.
The app is already translated into most European languages, so a launch in a new market does not wait on translation.
Talk to your account manager to start.
## Dependencies & limitations
* **Branded apps trail Spirii Go.** Features arrive after they have been validated in Spirii Go, so a branded app runs a release or two behind.
* **Home charging needs a validated charge box.** Smart home charging works on models Spirii has validated for it, typically Zaptec Go, Easee, and Amina C. Check with Spirii before promising it on other hardware.
* **You own the store accounts.** Both developer accounts need to exist before an app can be published, and maintaining them stays with you.
* **A branded app is a subscription.** The fee covers development, maintenance, and continuous updates.
## Related
If you are weighing a branded app, the app user record is what you would own — start there.
The driver record behind every app account, and who can see it.
Access and pricing you grant to drivers, redeemed in either app.
Branding Connect for your customers, and the name drivers see for your locations.
Physical and virtual charge keys drivers add to their account.
# Dynamic load management
Source: https://docs.spirii.com/capabilities/energy-management/dynamic-load-management
Fit more chargers onto the grid connection you already have.
Dynamic load management (DLM) shares a circuit's available power across the chargers connected to it, recalculating every time a vehicle starts or stops charging, so the fuse is never exceeded.
## Overview
A charger left to itself delivers whatever the vehicle asks for, first come first served. Put four of them on one circuit and the first two vehicles can take everything the fuse allows, leaving nothing for the next arrival — or tripping the fuse and taking the site down. The usual fix is a bigger grid connection, which is slow and expensive.
DLM is the alternative. It treats the fuse capacity as a budget and divides it among the connectors that are actually drawing power, so you can put more chargers on the connection you already have.
A **circuit** is the platform's representation of the physical electrical circuit your chargers are wired to in the cabinet on site. It holds a fuse capacity, set in amps, and larger installations can break it into sub-circuits. A circuit normally covers one geographical site, but it isn't tied to a single [location](/components/charging/locations): several floors of a car park, or two operators sharing a DC hub, can sit on one circuit.
## How it works
DLM works from three inputs: the circuit's fuse capacity, the maximum current each connector is rated for, and which connectors are drawing power at this moment.
Every connector that is actively charging is first guaranteed a floor of **6 A**. Whatever capacity remains is then split in proportion to how much headroom each connector has above that floor, so a connector rated for more current receives a larger share than a smaller one beside it. Connectors that are idle, unavailable or faulted are left out of the calculation entirely, and their share goes to the vehicles that can use it.
The whole circuit is recalculated from scratch whenever something changes:
```mermaid theme={null}
flowchart TD
T("A connector changes status, a charger joins or leaves the circuit, the fuse capacity changes, or an external limit arrives") --> R("DLM recalculates the whole circuit")
R --> P("Each charger receives an updated charging profile")
P --> O("Connectors adjust their output current")
```
### A worked example
A depot circuit is fused at 200 A and feeds three identical connectors. With all three charging, each is allocated roughly 66 A. When two of the vehicles finish, the remaining one is free to take its full rated current, up to the fuse limit.
Scarcity is where the 6 A floor starts to bite. On a 40 A circuit with seven vehicles plugged in, there isn't enough capacity to give all seven their minimum: six charge at the floor and the seventh is held at 0 A until capacity frees up. The vehicles that get the minimum are the ones whose sessions started first. The small amount left over — 4 A in this case — is spread across the six, taking each to about 6.6 A.
That behaviour is deliberate. A connector below 6 A can't deliver usefully, so the platform would rather charge six vehicles slowly than seven not at all.
## Options and configuration
| You set | Where | Why you would change it |
| - | - | - |
| Fuse capacity, in amps | The circuit in Connect | It has to match the physical fuse protecting the installation |
| Which charge boxes belong to the circuit | The circuit in Connect | Chargers on the same physical supply belong on the same circuit |
| Sub-circuits | The circuit in Connect | A large installation where groups of chargers sit behind their own fuses |
The capacity itself is a fixed number, which suits a site where the chargers are the only significant load. Where they aren't — a building drawing from the same connection, on-site solar, a battery — the limit needs to move during the day. That's [programmatic charger control](/capabilities/energy-management/programmatic-charger-control), which lets external software raise and lower the circuit limit while DLM keeps distributing whatever is available. The industry calls the combination advanced dynamic load management (aDLM).
## When to use it
DLM lets you put the next four chargers on the existing connection instead of waiting on an upgrade. Overnight there is usually slack in every session, so a smaller share per vehicle costs you nothing.
One circuit spanning the floors keeps the whole installation inside the building's supply.
Proportional distribution means a 150 kW unit isn't held to the same allocation as an 11 kW one beside it.
## Set up
DLM is configured in Connect, on the circuit.
DLM runs only on charger models Spirii has validated for it. Validation is assessed per model and per firmware version, so confirm with Spirii before you plan around a specific unit.
Enter the capacity in amps, matching the fuse that protects the installation.
Attach every [charge box](/components/charging/charge-boxes) wired to that supply.
From that point the circuit rebalances automatically.
## Dependencies and limitations
* **Validated charger models only.** Feature validation is per model *and* per firmware version — a model validated two years ago can fall out of compliance after a firmware update. This is what keeps the fuse protected, so it isn't waived.
* **Some chargers run their own load management in hardware.** Those setups don't integrate with Spirii's DLM; the two would work against each other. Pick one.
* **A connector that can't be given 6 A is given nothing** until capacity frees up, with the oldest session served first.
* **An unresponsive charger is treated as though it is still drawing its last known limit**, and is taken out of the balancing pool until it answers again. The circuit stays protected, but the capacity it is assumed to be using isn't offered to anyone else.
* **DLM is the outer boundary, not a competitor to the other capabilities.** [Grid balancing](/capabilities/energy-management/grid-balancing), [programmatic charger control](/capabilities/energy-management/programmatic-charger-control), [prioritised charging](/capabilities/energy-management/prioritised-charging) and [scheduled charging](/capabilities/energy-management/scheduled-charging) all work inside the limit DLM sets.
## Related
Let external software move the circuit limit as conditions on site change.
Give chosen vehicles the maximum available power while a limit is active.
How the four local capabilities resolve when more than one applies.
The units whose output DLM adjusts, and where firmware is managed.
# Energy management
Source: https://docs.spirii.com/capabilities/energy-management/energy-management
The four capabilities that decide how much power each charger draws, and when.
Energy management is Spirii's portfolio of local capabilities for distributing, scheduling, and controlling charging power. Add chargers without expensive grid upgrades, lower energy costs, and protect a site's electrical infrastructure.
## Overview
At a busy site, chargers left to draw power first-come-first-served can overload the circuit's fuse and leave vehicles undercharged. Adding more chargers can mean a costly grid-connection upgrade. Energy management solves both at the site, with four capabilities:
Distributes available power across the chargers on a circuit, within its fuse limit. The foundation everything else builds on.
Holds a session until the hours you chose, or until the cheapest intervals in a window.
Gives chosen charge keys the maximum available power ahead of the rest.
Lets your own software set charger and circuit limits dynamically.
All four work locally, on the circuit your chargers are wired to.
[**Grid balancing**](/capabilities/energy-management/grid-balancing) is the portfolio-level sibling: it earns revenue from frequency regulation rather than cutting a single site's costs. The two aren't independent, though. Grid balancing trims charging power within the boundary DLM sets, and it does so through programmatic charger control — second in the precedence order below.
## How it works
All four capabilities can be active on the same location and circuit at once. When more than one applies, they resolve in a fixed order of precedence:
```mermaid theme={null}
flowchart TD
A("Dynamic load management\nalways on, to keep the fuse protected") --> B("Programmatic charger control\nan external actor sets the limit")
B --> C("Prioritised charging\ncritical vehicles get power first")
C --> D("Scheduled charging\ncharges in the chosen or cheapest hours")
```
Fuse protection always comes before optimisation, so DLM wins. Scheduled charging only acts when nothing above it needs the power, which is why a full charging duration inside a window isn't guaranteed on a busy circuit.
Two consequences worth knowing before you enable anything:
* **Prioritised charging does nothing on its own.** It biases an allocation, so it needs DLM or a schedule to be limiting power in the first place.
* **Programmatic charger control is how the platform reaches outside itself.** Grid balancing uses it, and so does any energy management system, battery controller, or solar integration you bring.
## Options and configuration
| Capability | What it does | Use it when |
| - | - | - |
| [Dynamic load management](/capabilities/energy-management/dynamic-load-management) | Shares power across the chargers on a circuit, within the fuse limit | Always, since it's the foundation that keeps the site safe and operable |
| [Scheduled charging](/capabilities/energy-management/scheduled-charging) | Moves charging into chosen hours, or the cheapest intervals of a window | Vehicles stay plugged in longer than they need to charge |
| [Prioritised charging](/capabilities/energy-management/prioritised-charging) | Gives prioritised charge keys the maximum available power first | Some vehicles must charge fast regardless of the others |
| [Programmatic charger control](/capabilities/energy-management/programmatic-charger-control) | Lets external software set dynamic charger and circuit limits | You run an energy management system, solar, or a battery that should drive charging |
## When to use it
DLM lets you add chargers within the existing connection instead of paying for an upgrade. Add scheduled charging so the fleet charges overnight at the cheapest hours.
Programmatic charger control lets your software push charging toward solar production and hold the site within its grid-connection limit.
Prioritised charging keeps the must-run vehicles full while the rest share the remaining power.
## Set up
Most of energy management is yours to configure in Connect: you create the circuit and set its fuse capacity, attach the chargers, enable DLM, build schedules on the location's Power management tab, and mark locations and charge keys for prioritisation. Each capability's page covers its own steps.
Two things involve Spirii. Charger models have to be validated for the feature you want, which Spirii confirms as part of enrolment; and for programmatic charger control, Spirii registers your software as an actor and issues its credentials.
## Dependencies and limitations
* **Validated hardware only.** These capabilities run on charger models Spirii has validated for them, which is what keeps the fuse protected. Validation is assessed per model and per firmware version, so a model validated in the past can fall out of compliance after a firmware update. See [Charger validation](/capabilities/connection/charger-validation).
* **Programmatic charger control needs software you provide.** Spirii exposes the limits; the logic that decides what they should be is yours.
* **Prioritised charging needs an active power limit** to have any effect, and it works only on the Spirii network, not on roaming.
* **Price optimisation depends on electricity price data** for the market the location sits in.
## Related
Start with dynamic load management: it's the boundary everything else works inside.
The portfolio-level sibling: earn revenue from frequency regulation within the limit DLM sets.
Send dynamic power limits from your own software, and receive the resulting events.
Where schedules and prioritisation are configured for the chargers on a site.
The physical units whose power draw energy management adjusts.
# Grid balancing
Source: https://docs.spirii.com/capabilities/energy-management/grid-balancing
Earn from your portfolio's flexibility.
Grid Balancing earns you revenue for making small, brief adjustments to charging power when the electricity grid needs them.
## Overview
An electricity grid stays stable only while production and consumption match. When they do, frequency sits at 50 Hz. Fossil production made that straightforward: if consumption rose, you burned more fuel. Wind and solar do not take instructions, so production has become the unpredictable side of the equation.
Flexibility has therefore moved to consumption, and EV chargers are unusually well suited to providing it. Trimming a charger from 11 kW to 9 kW for a few seconds is immaterial to the driver. Aggregate that across thousands of chargers and it becomes a resource a transmission system operator (TSO) will pay for.
Grid Balancing is how your portfolio sells that flexibility. Spirii offers two services, and the difference between them is how the adjustment is triggered.
A reflex. Each charger reacts to the frequency it measures itself, cutting power within 30 seconds when the grid drops below 49.5 Hz.
A setpoint. The TSO sends a target every few seconds and the portfolio tracks it, holding reserve headroom to move within.
Grid Balancing works across your portfolio to earn revenue. The local energy management capabilities — Load Balancing, Price Optimised Charging, Prioritised Charging, Programmatic Charger Control — work at a single site to cut energy costs and protect the circuit. Different jobs, and you can run both.
## How it works
Both services follow the same daily cycle.
Each day, a balance responsible party (BRP) forecasts how much flexible power your enrolled portfolio will have available tomorrow.
Spirii bids that flexibility into the TSO's market at a price, through the BRP. Spirii cannot sell to a TSO directly, so a BRP partnership is part of the service in every market.
The TSO buys the cheapest bids that meet its need. Several providers compete, which is why a market exists at all.
When the grid needs balancing, the TSO's signal reaches Spirii through the BRP, and charging power across the enrolled portfolio adjusts.
You are paid for the flexibility your portfolio made available.
### FCR-D up
Frequency containment reserve for disturbances is the TSO's first line of defence. When frequency falls below 49.5 Hz, enrolled chargers reduce power within 30 seconds, and that reduction in consumption helps frequency recover.
The "up" means the frequency is pushed up, by consuming less.
FCR-D pays on one component: the **capacity market**, for being available and ready. You are paid whether or not the reserve is called on.
### aFRR
Automatic frequency restoration reserve takes over from FCR-D after roughly 30 seconds, bringing frequency back to 50 Hz rather than merely arresting its fall.
Rather than reacting to what each charger measures, the portfolio keeps headroom in its consumption: a reserve it can move within. The TSO then sends signals every few seconds telling it how much to increase or decrease.
aFRR pays on two components:
* The **capacity market**, for holding that headroom available
* The **energy activation market**, for the energy actually delivered when the TSO calls on it
### Working alongside local energy management
Grid Balancing sits directly beneath Load Balancing in the order things resolve. Load Balancing always comes first, because the fuse has to be protected. Grid Balancing then reduces power inside that boundary, and whatever is left is what the optimisation capabilities have to work with.
```mermaid theme={null}
flowchart TD
A("Load Balancing\nthe circuit's fuse limit") --> B("Grid Balancing\nreduces power within that limit")
B --> C("Optimisation capabilities\nwork with what remains")
```
Three properties define how it behaves at a site.
Both services are up-regulation: they help frequency recover by consuming less. Grid Balancing never asks a charger for more power than it was already drawing, so it cannot push a circuit toward its limit.
Consider a location with two 75 kW chargers on a circuit fused at 100 kW, Load Balancing enabled, and both chargers mid-session at 50 kW.
An activation asks charger A to drop to 30 kW. Charger A reduces, and the 20 kW it releases stays unused — Load Balancing does not pass it to charger B. If it did, the site would consume exactly as much as before and nothing would have been balanced.
A charger with no vehicle connected has no power to reduce, which is why the available flexibility is forecast daily rather than fixed.
### What drivers experience
Grid Balancing is designed to be close to invisible, and for FCR-D it is. Activations trim power by a few percentage points and usually last under ten seconds, frequently a fraction of a second. No driver notices a micro-adjustment on that scale.
aFRR reserves more power and holds it for longer, up to fifteen minutes, so a driver charging through an activation may see their power drop.
Your lever is **hours**. You choose when your portfolio bids, so a network built on overnight home charging can offer flexibility while its drivers are asleep and leave daytime sessions alone.
Adjustments apply to all charging on an enrolled charger, whoever the driver is and whichever app or contract they arrived with.
Charging resumes when an activation ends. Spirii holds safeguards that return enrolled chargers to normal power independently of the balancing signal, so a signal that fails to arrive does not leave a charger throttled.
## Options & configuration
You keep control of how much of your portfolio is exposed, when, and at what price.
| Control | What you set | Why you would change it |
| - | - | - |
| Capacity | Which chargers are enrolled, and what share of the forecast to bid | Start with a subset while you build confidence, then increase it |
| Hours | Bid around the clock, or only in chosen windows | Confine flexibility to periods where a power reduction costs you nothing |
| Price | The compensation you are willing to accept | A lower price wins more bids; a higher one is selected less often but pays better when it is |
Choosing between the two services is mostly a question of portfolio size and driver tolerance:
| | FCR-D up | aFRR |
| - | - | - |
| Trigger | The charger's own frequency measurement | A TSO setpoint every few seconds |
| Response | Within 30 seconds | Continuous through the activation |
| Duration | Seconds | Up to 15 minutes |
| Paid for | Availability | Availability and delivered energy |
| Driver impact | Not perceptible | Possibly perceptible |
Minimum bid sizes apply, they differ by service and by market, and they determine which services your portfolio can reach at all. Spirii confirms what your portfolio qualifies for during enrolment.
## When to use it
**A large base of home or workplace charging.** Vehicles plugged in overnight for far longer than they need are the ideal resource: there is slack in the session, and a fifteen-minute reduction at 3 am changes nothing for the driver.
**A depot fleet charging between shifts.** The same logic, with the added benefit that you control the vehicles and the schedule, so you know exactly how much slack exists.
## Set up
**Prerequisites**
**Market.** Grid Balancing is available in Denmark, across both the DK1 and DK2 grid zones.
**Validated hardware.** Enrolment runs on charger models Spirii has validated for Grid Balancing specifically.
**Portfolio size.** Minimum bid sizes mean a portfolio has to reach a certain scale before it can participate.
Talk to your account manager to get started.
### Why hardware validation is separate
Grid Balancing asks more of a charger than ordinary charging does. A charger has to report metering fast enough for a TSO's timescales, accept dynamic power limits reliably, and hold a session open while delivering zero power without terminating it. Plenty of models on the market cannot do all three, so validation for Grid Balancing is assessed per model rather than inherited from a charger being supported for charging.
## Dependencies & limitations
* **Denmark only.** The service runs in the DK1 and DK2 grid zones.
* **Validated models only.** A charger model has to pass Grid Balancing validation before it can be enrolled, which is a higher bar than support for charging alone. See [Charger validation](/capabilities/connection/charger-validation).
* **A balance responsible party is always involved.** Spirii reaches a TSO through a BRP rather than directly, in every market.
* **aFRR can be perceptible to drivers.** Activations of up to fifteen minutes may show as reduced power. Bidding hours are how you manage that exposure.
* **Enrolment is handled by Spirii.** Chargers are added to and removed from Grid Balancing on your behalf.
## Related
Load Balancing is the boundary Grid Balancing works inside, so it is worth understanding before you enrol.
Load Balancing, Price Optimised Charging, Prioritised Charging, and Programmatic Charger Control.
The units whose power Grid Balancing adjusts.
Where local energy settings are configured, and how chargers are grouped.
How the energy delivered during an activation is still recorded and billed.
# Prioritised charging
Source: https://docs.spirii.com/capabilities/energy-management/prioritised-charging
Keep the vehicles that can't wait at the front of the queue when power is short.
Prioritised charging gives a chosen vehicle the maximum power available at its connector whenever the site's power is being limited, ahead of everything else charging there.
## Overview
On a site where the fuse can't supply every charger at once, power is shared. That is the point of [DLM](/capabilities/energy-management/dynamic-load-management) — but an even share is the wrong answer for an ambulance, a police car, or the one van that has to be out at 05:00 whatever else happens.
Prioritised charging is the exception mechanism. Priority travels with the [charge key](/components/access/charge-keys), not with the vehicle or the connector: mark a key as prioritised, and any session authorised with it is prioritised at any location where you've allowed prioritisation.
Prioritised charging only does something when a power-limiting capability is active on the location. With no limit in place, every connector already delivers full power, so there is nothing to prioritise and priority keys are simply ignored.
## How it works
Two settings have to line up: the location has to accept prioritised sessions, and the charge key has to be marked as prioritised. When a session authorised with that key starts on that location, it is allocated the maximum power it can draw, and the remaining capacity is shared among the other vehicles under the normal distribution rules.
```mermaid theme={null}
flowchart TD
A("Session authorised with a prioritised charge key") --> B("Location accepts prioritised sessions?")
B -->|"yes, and a power limit is active"| C("Maximum available power to this connector")
B -->|"no, or no limit active"| D("Normal distribution")
C --> E("Remaining capacity shared among the other sessions")
```
When two prioritised vehicles charge at the same time, they split the available power evenly, each up to the maximum it can draw. Everything else on the circuit shares what is left, which on a tight circuit is very little. Priority is a blunt instrument by design, so mark keys sparingly — a fleet where half the keys are prioritised has no priority at all.
### What it does to the other capabilities
* **With DLM**, the prioritised session is served first from the circuit's capacity, then the rest is distributed.
* **With [scheduled charging](/capabilities/energy-management/scheduled-charging)**, a prioritised session ignores the schedule and charges immediately rather than waiting for the next selected interval.
* **With [grid balancing](/capabilities/energy-management/grid-balancing)**, priority does not win. Grid balancing sits above prioritised charging in the order things resolve, so a frequency activation still trims power on an enrolled charger.
### A worked example
A municipal depot runs eleven vans and two rapid-response vehicles on a circuit that can't supply them all at full power. The two response vehicles carry prioritised keys; the vans don't. On a normal night all thirteen share the circuit. When a response vehicle plugs in at 02:00, it takes the maximum its connector can deliver and the vans absorb the reduction between them. Nobody reconfigures anything, and the operator doesn't have to decide in the moment who matters.
## Options and configuration
| Setting | Where | Effect |
| - | - | - |
| Allow prioritisation | The location, in Connect | Prioritised keys have an effect here. Off by default, and with it off the setting on the key does nothing |
| Prioritised | The charge key, in Connect | Every session authorised with this key is prioritised, at any location that allows it |
Both lists can be filtered on the setting, so you can see at a glance which locations accept prioritisation and which keys carry it. Completed sessions can be filtered by whether they were prioritised, which is how you check after the fact that priority went where you intended.
## When to use it
The original case: the vehicle has to leave with as much charge as it can get, and a fair share isn't good enough.
Refrigerated transport, on-call service vans, the vehicle covering the early shift.
Priority keys as a paid service for tenants or members who want the fastest charge available.
## Set up
Both settings are yours to make in Connect; there is nothing to enable on Spirii's side.
Prioritised charging has no effect on a location where nothing is limiting power. If the site has neither DLM nor a schedule, start there.
Edit the location and switch prioritisation on.
Edit each key that should carry priority.
## Dependencies and limitations
* **A power limit has to be active.** Without DLM or a schedule on the location, the platform has no allocation to bias and priority keys behave like any other.
* **Priority belongs to the key, not the vehicle.** Anyone charging with that key is prioritised, on any location that accepts it.
* **Spirii network only.** Priority doesn't travel over roaming — a prioritised key charging on another operator's network is treated as an ordinary session.
* **Grid balancing still applies.** An enrolled charger can be trimmed during an activation regardless of who is plugged into it.
* **The same charger model validation applies** as for the rest of energy management, per model and per firmware version.
## Related
Where priority is set, and how keys are issued to drivers.
The limit that makes priority meaningful in the first place.
A prioritised session charges immediately instead of waiting for its window.
Where a completed session records whether it was prioritised.
# Programmatic charger control
Source: https://docs.spirii.com/capabilities/energy-management/programmatic-charger-control
Hand the power decisions to your own software, and keep the fuse protected while it runs.
Programmatic charger control lets external software set power limits on your chargers and circuits through the Energy Management API, so charging can follow solar output, a battery's state of charge, building load, or a signal from your own systems.
The integration model, channels, payloads and examples.
## Overview
[DLM](/capabilities/energy-management/dynamic-load-management) distributes a fixed budget. Plenty of sites don't have a fixed budget: the building draws power through the day, the roof produces some, a battery absorbs and releases more, and the amount left for chargers moves minute by minute. Deciding how much that is takes software that can see all of it — an energy management system, a battery controller, a smart meter integration, your own platform.
Programmatic charger control opens that door. Spirii registers your software as an **actor**, grants it control over specific charge boxes and circuits, and from then on it can move limits up and down inside the boundaries Spirii enforces. DLM keeps distributing whatever the actor makes available, which is what the industry calls advanced dynamic load management (aDLM).
## How it works
An actor works in two directions. Control requests go out over HTTP to a single endpoint that accepts every command type; the response only confirms the request was authenticated and queued, not that it was applied. The outcome arrives separately, as a message on one of the actor's SNS topics, correlated by the `request_id` the actor chose. Spirii publishes results and telemetry to those topics: control responses, connector status updates, asset master data, and near-real-time power measurements.
Four commands are available today:
| Command | Target | What it does |
| - | - | - |
| `SET_EVSE_INPUT_LIMIT` | A connector | Caps the current or power that connector may draw |
| `CLEAR_EVSE_INPUT_LIMIT` | A connector | Removes that cap |
| `SET_CIRCUIT_FUSE_LIMIT` | A circuit | Temporarily overrides the circuit's fuse capacity, in amps |
| `CLEAR_CIRCUIT_FUSE_LIMIT` | A circuit | Removes the override and any pending fallback |
Every limit is temporary. Each request carries a `valid_to` timestamp, at least 15 seconds in the future, and when it passes the asset returns to its normal state on its own. A limit you forget to clear expires; a limit you want to hold has to be renewed.
Requests are rate limited to one every 5 seconds, tracked separately for each asset and each action, which is roughly the time a charger needs to apply a profile and report back.
### Choosing what happens to the capacity you release
When you cap a connector on a circuit running DLM, you decide what happens to the difference:
| `distribution_strategy` | Effect | Use it when |
| - | - | - |
| `DISTRIBUTE` (default) | The freed capacity goes to the other connectors on the circuit | You want to slow one vehicle down but keep the site's total consumption high |
| `HOLD` | The freed capacity goes unused | You want to reduce what the site draws overall — the whole point of the reduction |
Getting this backwards is the common mistake. Capping one connector with `DISTRIBUTE` while trying to cut site consumption achieves nothing: the power simply moves next door.
### A worked example
A public CPO runs a DC site behind a battery that buffers the grid connection. The battery's controller is registered as an actor and holds the circuit limit at 360 A, roughly 250 kW, while the battery has charge to give.
When the battery's state of charge drops below its threshold, the controller sends a circuit limit of 0 A and the chargers stop drawing until it recovers. Every request also carries a fallback: 43 A — about 30 kW, the level the grid connection can carry unaided — to apply 300 seconds after the request. If the controller goes quiet, or the meter it reads drops out, that fallback takes over five minutes later and the connection stays inside its limit without anyone intervening.
The fallback is the part worth copying. Software that controls power has to fail safe, and the platform will hold that position for you rather than reverting to full capacity.
## Options and configuration
Control is granted per asset. A charge box or circuit is subscribed to an actor, and the actor is told about it on its master data topic; unsubscribing sends the same message in reverse. One asset can be subscribed to several actors as long as they hold different capabilities — but two actors can't hold the same capability on the same asset, because two systems setting the same limit would fight.
Limits on connectors can be given in watts or amps. Where a conversion is needed, Spirii uses its own phase and voltage data for the connector unless the request overrides it, which is worth doing on sites where conditions fluctuate and precision matters.
## When to use it
Your controller already knows how much power is available; this is how it tells the chargers.
Hold the chargers inside whatever the building isn't using, and avoid a capacity charge or an upgrade.
Priority rules, time-of-use strategies, or a model that beats the platform's defaults for your operation.
Spirii's own [grid balancing](/capabilities/energy-management/grid-balancing) service runs through this same mechanism, which is the clearest illustration of what it can carry.
## Set up
Actor registration is done by Spirii, not self-serve.
Spirii registers the actor, issues its API key, creates its topics, and subscribes the charge boxes and circuits it should control.
Any valid SNS subscription protocol works — an SQS queue, an HTTPS callback, a Lambda. Subscriptions can be changed later.
Payloads, examples and rejection reasons are in the [Energy Management API reference](/capabilities/smart-charging/overview).
## Dependencies and limitations
* **You bring the software.** Spirii exposes the controls; the logic that decides what the limits should be is yours or your supplier's.
* **A limit is a ceiling, not a guarantee.** It caps what a connector may draw. It doesn't promise the vehicle will draw that much, and it doesn't reserve capacity — DLM may still allocate less on a busy circuit.
* **Circuit limits need DLM enabled on that circuit**, and can be set between 0 and the configured circuit capacity. Without DLM, the request has no effect.
* **Connector limits apply to live sessions.** The connector has to be `Charging`, `SuspendedEVSE` or `SuspendedEV`. Setting a limit doesn't itself start charging — a connector suspended by a schedule stays suspended.
* **Hardware and user-set limits win.** A control request can't lift a connector above what the hardware or the operator's own configuration allows.
* **Active schedules override connector limits.** Outside a schedule's selected periods the effective limit is 0, whatever the actor asked for.
* **The API sets limits; it doesn't create schedules.** Charging schedules are configured in Connect.
* **Validated charger models only**, assessed per model and per firmware version.
## Related
The integration model, channels, payloads and examples.
The four commands in full, with constraints and examples.
What distributes the capacity an actor makes available.
Spirii's own service, built on this mechanism.
# Scheduled charging
Source: https://docs.spirii.com/capabilities/energy-management/scheduled-charging
Move charging to the hours that cost you least, without anyone deciding when to plug in.
Scheduled charging decides when a connected vehicle actually draws power: either inside a window you choose, or in the cheapest intervals the platform can find within that window.
## Overview
A vehicle plugged in at 18:00 charges at 18:00, at whatever electricity costs then — even when nobody needs it until six the next morning. On a depot with twenty vehicles doing that every evening, the difference between charging at the day's peak and charging at its trough is most of the energy bill.
Scheduled charging closes that gap. You define a schedule against the connectors at a location and the platform holds the session, releasing power only when the schedule says so. Drivers plug in as usual and see a connected but idle session until charging starts.
It runs in two modes.
Use it when you know the hours you want charging to happen in — a fixed night tariff, or a window that suits the depot's shifts.
Use it when prices move through the day and vehicles are plugged in for longer than they need. The platform finds the cheapest intervals for you.
Price optimisation is the stronger option wherever spot prices apply, because it reacts to each day's prices instead of a guess made once. Scheduled mode is the right choice when the constraint is the operation rather than the price — vehicles that must be off the charger by a certain hour, or a site where charging outside set hours isn't wanted at all.
## How it works
For a price-optimised schedule, the platform divides the window into 15-minute intervals, fetches electricity prices for the market the location sits in, and selects the cheapest intervals that add up to the charging hours you asked for. It then sends the charger a charging profile telling it when to deliver power and when to pause.
```mermaid theme={null}
flowchart TD
A("Driver plugs in and authorises") --> B("Session held, connector occupied, no energy flowing")
B --> C("A selected interval begins, the charger delivers power")
C --> D("Interval ends, the session is held again if more intervals remain")
D --> C
C --> E("Charging hours delivered, or the driver unplugs")
```
While a session is held, the connector reports `SuspendedEVSE` — the vehicle is ready and the charger is deliberately not offering current. In Connect's ongoing sessions view it shows as suspended rather than charging, which is expected and not a fault.
### A worked example
A logistics depot's vans return between 17:00 and 19:00 and leave at 06:00. The operator sets a window of 19:00 to 06:00 with six charging hours and price optimisation on. A van plugged in at 17:30 sits connected and idle until the platform's first selected interval, charges through the cheapest six hours of the night in 15-minute blocks, and is full before the shift starts. Nobody on the team decided anything after the van was plugged in.
### Where it sits against the other capabilities
Scheduled charging has the lowest precedence of the local energy capabilities. [DLM](/capabilities/energy-management/dynamic-load-management), [programmatic charger control](/capabilities/energy-management/programmatic-charger-control), [prioritised charging](/capabilities/energy-management/prioritised-charging) and [grid balancing](/capabilities/energy-management/grid-balancing) can all reduce or pre-empt power during an interval the schedule had selected.
If enough intervals are cut short by a capability above it, the full charging duration you asked for may not be delivered within the window. On a busy shared circuit, leave more window than the bare minimum.
## Options and configuration
Schedules are created on a location's **Power management** tab in Connect and assigned to connectors there. What you set:
| Setting | What it does |
| - | - |
| Start and end time | The window during which the vehicle is expected to be connected |
| Optimise for lowest prices | Switches the schedule from fixed hours to cheapest-interval selection |
| Number of charging hours | How many hours of actual power delivery are needed inside the window |
| Enabled or disabled | Turns a schedule off while keeping its settings |
Editing a schedule affects the next transaction, not the one in progress. The same holds for deleting one: a session already running is left alone.
Who can do what follows the standard Connect [roles](/capabilities/account/roles).
For drivers charging at home or on a company car charger, the same logic is available in [Spirii Go](/capabilities/driver-experience/spirii-go-and-branded-apps), set by the driver on their own charger.
### Overriding a schedule
When a vehicle needs charging now, open the ongoing session in Connect and choose **Override schedule**; drivers do the same from the session view in Spirii Go. Charging starts immediately, and the override applies for the rest of that transaction — including any later windows, if the vehicle stays plugged in across days. Unplugging and starting a new session returns to normal scheduled behaviour.
## When to use it
Vehicles stand for eleven hours and need four. Price optimisation takes the difference straight off the energy bill.
Fixed hours are enough here; there are no intra-day prices to chase.
Drivers set it once in Spirii Go and stop thinking about it.
## Set up
Schedules can only be assigned to connectors on models Spirii has validated for smart charging. Connect flags anything else as incompatible when you try.
Schedules live with the location, not with the individual charger.
Set the window, switch on price optimisation if you want it, and enter the charging hours needed.
The schedule takes effect on the next session at those connectors.
## Dependencies and limitations
* **Price optimisation needs price data for the market.** It is available in Austria, Belgium, Denmark, Estonia, Finland, France, Germany, Latvia, Lithuania, the Netherlands, Norway, Poland, Portugal, Spain, Sweden and the United Kingdom. Elsewhere, the cheapest intervals can't be calculated.
* **One schedule per connector, and schedules can't overlap.** Connect and the platform both refuse an overlapping assignment.
* **Schedules are assigned per location.** There's no way to apply one schedule across chargers at several locations in a single action.
* **A vehicle still connected when the window closes stays suspended.** Power doesn't resume until the next window starts or someone overrides.
* **The full duration isn't guaranteed.** Capabilities above scheduled charging in the precedence order can take back intervals it had selected.
* **Validated models only**, and validation is per model and per firmware version. A charger that has never connected to Spirii also shows as incompatible until it establishes its first OCPP connection.
The charger has to accept and apply charging profiles from Spirii. In practice that means:
| Requirement | Detail |
| - | - |
| OCPP version | 1.6J. SOAP transport and earlier versions aren't supported |
| Smart charging | `SetChargingProfile` and `ClearChargingProfile` |
| Profile purpose | `TxProfile` and `TxDefaultProfile` |
| Profile kind | `Relative` |
| Schedule granularity | 15-minute periods |
| Stack levels | At least 6 |
| Spirii validation | The model has to be on Spirii's validated list |
Claimed support and working support are not the same thing, which is why validation is tested per model rather than read off a datasheet.
## Related
The circuit limit every schedule works inside.
A prioritised charge key skips the schedule and charges immediately.
What the driver pays is set separately from when the vehicle charges.
Where drivers set and override schedules on their own charger.
# Charger history and logs
Source: https://docs.spirii.com/capabilities/operation-monitoring/charger-history-and-logs
Work out what a charge box did, and when it did it.
Every charge box keeps a record of when it was connected, what state its EVSEs reported, and every OCPP message it exchanged with the platform. All of it is readable in Spirii Connect.
## Overview
When a charger misbehaves, the question worth answering first is which layer is broken. A charge box holds its own history at three levels of depth, and each one rules something in or out.
| Question | Where to look | Level |
| - | - | - |
| Was it reachable at all? | Connectivity history | Charge box |
| What state was the outlet in? | Status history | EVSE |
| What exactly did it say? | OCPP logs | Individual message |
Work down the list, not up from the bottom. A charge box that was offline for the hour in question explains itself, and reading OCPP messages to discover that takes far longer than reading connectivity history.
All three open from the three-dot menu on any table that lists charge boxes or EVSEs: a location's **Charge boxes** tab, the **Connectors** page, and **Operations → Monitoring**. Connectivity history and OCPP logs sit on the charge box; status history sits on the EVSE.
None of it ages out. All three records reach back to the charge box's first connection and are kept from then on.
## Connectivity history
The charge box's connectivity history records when it connected to the platform and when it dropped. It also shows whether a drop is a one-off or a pattern.
A charge box that has reconnected fifteen times this week is telling you something different from one that dropped once. The first is usually a network or power problem at the site; the second may be nothing at all.
There is no date filter here, so reaching an older event means paging back to it.
## Status history
An EVSE's status history records its charging status over time, and when each change happened. Where connectivity history tells you whether the charge box was talking, status history tells you what it was talking about.
This is where you separate a fault from a driver's experience of one. An EVSE that moved to Preparing and back to Available without charging did not fail in the way an EVSE that reported Faulted did, and the two need different conversations with the hardware manufacturer.
Status history pages the same way, and has no date filter either.
## OCPP logs
OCPP logs are the full message-level record of a charge box's conversation with the platform. Each entry carries the request and the response as JSON. You see precisely what was asked and what came back.
Recent entries load with the page; anything older than the last couple of days is retrieved from storage. Use the timestamp filter to reach it, and expect the query to take longer than a page of recent traffic.
Two filters narrow the list:
* **Timestamp** — the window you care about, and the way to reach older records
* **Message type** — any of the OCPP 1.6 message types
The JSON appears as the charge box sent it, including the charge key identifiers carried in authorisation requests.
## A worked example
A driver reports that EVSE `DE*SPI*E00012345` at `Munich DC Hub` would not start a session on the afternoon of Tuesday 22 Apr 2025.
The charge box held an unbroken connection across that window. It was reachable, which rules out the site's network.
The EVSE moved to Preparing at 14:11 and back to Available at 14:13, with no charging in between. The driver plugged in and the charger acknowledged it: the cable and the socket did their job.
Filtered to that two-minute window, they show the authorisation request the charge box sent and the response it received. That is the exchange that decided whether the session began.
## Dependencies & limitations
* **Connectivity and status history have no date filter.** Reaching an older event means paging back through the list. Only the OCPP logs carry a timestamp filter.
* **Older OCPP entries are slower to load.** Anything beyond the last couple of days is fetched from storage, so narrow the timestamp window before you run the query.
* **Message types follow OCPP 1.6.** The filter's options are the OCPP 1.6 message set.
* **These three views are Connect-only.** The Spirii API has no endpoint for connectivity history, status history, or OCPP logs, and none of them appear in [Exports](/capabilities/reporting-analytics/exports). Read them in Connect, or capture what you need from the screen.
## Related
If you arrived here from an alert, start with connectivity history and work down.
The Monitoring list these views hang off, and the alerts that point you at one.
Acting on what the history tells you.
What every connector is doing right now, rather than what it did.
Which role each user needs, and what each one can do in Connect.
# Faults & alerts
Source: https://docs.spirii.com/capabilities/operation-monitoring/faults-and-alerts
Cut the time between a charger failing and you finding out.
The Monitoring list shows every charge box that is offline and every EVSE reporting a fault. Alerts email you when either happens.
## Overview
Uptime depends on how fast a failure reaches you. Spirii Connect gives you two ways to find out: a list you can work through, and an email for when nobody is looking at the list.
Everything currently offline or faulted, with the error codes the hardware sent and the tools to act on each one.
An email when a charge box goes offline or an EVSE reports a fault, anywhere in your network.
Both reflect what your charge boxes report. Statuses and error codes come from the hardware. What you see is the last thing that charge box sent.
## The Monitoring list
Find it in Connect under **Operations → Monitoring**. It lists every charge box currently offline and every EVSE currently in a faulted state, along with the error code and any information message the charge box has sent, and when each was last checked.
### Offline and faulted are different things
Connectivity belongs to the charge box; fault state belongs to the EVSE.
```mermaid theme={null}
flowchart LR
C("Charge box") -->|"online or offline"| L("Monitoring list")
C --> E("EVSE it holds")
E -->|"faulted, with an error code"| L
```
A charge box that has gone offline has stopped talking to the platform. The last status you have is the last one it managed to send. A faulted EVSE is different: its charge box is still connected and actively reporting a problem, which is why it can hand you an error code and a message.
### Who sees what
The list respects the customer hierarchy. Use [impersonation](/capabilities/account/impersonation) to narrow the view to a single customer's sites. Editors see the Monitoring list for the locations they have access to.
### Acting on a row
Each row carries the tools for that charge box or EVSE: remote commands, the OCPP logs, its configuration, and its status and connectivity history. The list is where you find the problem; those tools are where you work out what happened and act on it.
## Alerts
Alerts turn the Monitoring list into something that reaches you. You create one in Connect under **Settings → Alerts**, where each alert is a notification you subscribe to.
| Field | What it sets |
| - | - |
| Notification trigger | How the notification reaches you — email |
| Notification type | The condition you subscribe to, such as `evseOffline` |
| Email | The address to notify |
| Email subject | The subject line the email arrives with |
| Is active | Whether the notification is live. Clear it to switch an alert off without deleting it |
The trigger is the delivery channel, not the fault condition. The condition itself lives in **Notification type**, and that list carries other notifications alongside the charger ones.
The subject line is what you scan when three arrive at once. `Charger offline — Munich DC Hub` beats a generic line. The recipient does not have to be you: a shared operations inbox works.
### What fires, and when
An alert fires when a charge box goes offline or an EVSE reports a fault, anywhere in your network. A delay before sending means a charge box that drops and recovers within a few minutes never produces an email. That keeps a flapping connection out of your inbox, and every alert you do receive represents a fault that has persisted.
Alerts tell you when a fault is registered. The Monitoring list tells you what is affected right now — a charge box that has recovered drops off it.
## Dependencies & limitations
* **Alerts are network-wide.** A notification covers every charge box and every EVSE under your account, with no per-location scope. To watch a single site, filter the Monitoring list or narrow it with impersonation.
* **An offline charge box carries no error code.** It stopped reporting before it could send one. You get its connectivity and last-known status, and nothing more.
* **Brief interruptions never reach your inbox.** A charge box that drops and recovers inside the delay window produces no email. Its connectivity history still records the drop.
## Related
Once you have found a fault, remote commands are where you act on it.
Resetting, rebooting, unlocking, and the rest of what you can send to a charge box.
The live view across every connector, faulted or not.
What a charge box is, and how it relates to the EVSEs it holds.
What an EVSE is, and why the fault sits on it rather than on the charge box.
Which roles in your organisation can reach the Operations area.
# Firmware management
Source: https://docs.spirii.com/capabilities/operation-monitoring/firmware-management
Keep your charge boxes on current firmware without a site visit.
Firmware management lets you install manufacturer firmware on your charge boxes from Spirii Connect, one at a time or across every charge box of a model at a site.
## Overview
It sits in Connect under **Operations → Firmware Management**, for users with the Operator role. The page lists the charge boxes you can update, what firmware each is running now, and how any update in progress is going. You supply the firmware file from your hardware manufacturer; Connect uploads it to the charge box and reports what happens.
A charge box appears in the list when two things are true: Spirii has verified that its model supports remote firmware updates, and the charge box is online.
Pick one or more charge boxes from the list. Bulk selection works only across charge boxes of the same model and type.
Select a file you have already uploaded, or add a new one from your hardware manufacturer.
If a charge box is mid-session, the update waits until the charge box becomes **Available**.
The charge box is taken out of service and the firmware installs, typically in 10–15 minutes, though this varies by manufacturer.
The charge box returns to service on the new version, shown in its **Current firmware** column.
Installing firmware is the operator's responsibility. Obtaining the right firmware file from your hardware manufacturer, and confirming it suits the model, is yours to do; Spirii provides the tooling to upload a file and install it, and reports what the charge box returns.
## How it works
### Working in the owning customer's context
Charge boxes are owned by customers in your hierarchy, and firmware management acts in the owner's context rather than yours. To reach a charge box owned by one of your customers, use **Impersonate** from the Connect menu and pick that customer's account. The list then shows the charge boxes they own.
### What the firmware list shows
Each row gives you what you need to decide whether a charge box should be updated at all:
| Column | What it tells you |
| - | - |
| Serial number | Which physical unit the row refers to |
| Model type | The model, and therefore which firmware files apply |
| Connectivity status | Whether the charge box can receive an update right now |
| Current firmware | The version installed, so you can see what is behind |
| Installation status | How far an update has progressed |
| Retries | How many installation attempts have been made |
| Last updated | When the status last changed |
### Firmware files
Connect stores the firmware files you upload, scoped to your operator account. Each time you run an update you either pick a file you have already uploaded or add a new one.
When you upload a file you also record its **firmware version** and **release date**. Those two fields are what make a stored file identifiable months later, once a filename from a manufacturer's download page no longer tells anyone what it contains. Spirii hosts the file, and the charge box retrieves it when the installation runs.
### Installing and queueing
Select one or more charge boxes, choose a file, and start the update. Bulk selection works only across charge boxes of the same model and type, because a firmware file is written for a specific model.
If a charge box is mid-session, the update waits until its status is Available. Installation then makes the charge box unavailable for charging, and typically takes 10 to 15 minutes, though this varies by manufacturer. The **Installation status** column tracks progress and **Retries** shows how many attempts have been made.
An update cannot be cancelled once it has started, and there is no rollback to the previous version.
### A worked example
`Rheinstrom GmbH` operates a site owned by `Lindenhof Housing`, with six identical AC charge boxes. The manufacturer releases firmware `2.4.1`, fixing a metering fault.
Rheinstrom impersonates `Lindenhof Housing`, opens Firmware Management, and sees all six charge boxes listed as online and running `2.3.8`. Selecting all six is allowed because they are the same model. Rheinstrom uploads the manufacturer's file, records the version and its release date, and starts the update.
Four charge boxes are idle and begin installing straight away. The other two are mid-session, so their status shows as queued and installation begins when each driver finishes. Each row shows `2.4.1` as its current firmware once installation completes.
## When to use it
**A manufacturer releases a security or stability fix.** Select every charge box of that model at a site and install in one pass rather than working through them individually.
**Timing is worth planning.** Each charge box is out of service while it installs, so a bulk update takes a site's capacity down in stages. Running updates in a low-utilisation window costs fewer sessions than mid-afternoon at a busy hub.
## Dependencies & limitations
* **Verified models only.** A charge box appears in the list once Spirii has verified that its model supports remote firmware updates, following the same model-verification approach as other hardware-dependent features. Check with Spirii if a model you operate is missing, or see [Charger validation](/capabilities/connection/charger-validation).
* **The charge box must be online.** Offline charge boxes do not appear in the list.
* **Bulk updates need matching models.** You can select several charge boxes at once, but only of the same model and type.
* **Updates queue behind charging.** An update waits until the charge box status is Available, and a charge box in continuous use will keep waiting.
* **No charging during the update.** Expect 10 to 15 minutes out of service per charge box, varying by manufacturer.
* **No cancel and no rollback.** Once an update starts it runs to completion or fails, and the previous version cannot be restored.
* **Files are scoped to your operator account.** Uploaded firmware is not shared between operators.
* **Connect only.** There are no public API endpoints for firmware management.
## Related
Before your first update, confirm with Spirii that the charge box models you operate have been verified for remote firmware updates.
The hierarchy that decides which customer owns a charge box.
Which roles in your organisation can reach the Operations area.
What a charge box is, and how models and serial numbers identify one.
Other commands you can send to a charge box from Connect.
# Live status tracking
Source: https://docs.spirii.com/capabilities/operation-monitoring/live-status-tracking
Follow your network as it runs, and support a driver mid-session.
**Connectors** shows what every connector you operate is doing. **Ongoing sessions** shows every charging session in progress, on your own chargers and on other networks your drivers use.
## Overview
Both pages read the same live data from your charge boxes and shape it differently: Connectors gives you a row per connector, Ongoing sessions a row per session.
Your infrastructure, connector by connector. Status, power, consumption, and who is plugged in.
Every session in progress, on your chargers and on other networks your drivers use.
Both sit at the top level of Spirii Connect's main menu.
Connectors answers questions about your infrastructure: how many connectors are charging, which are faulted, where capacity is sitting idle. Ongoing sessions answers questions about a single driver and a single session, including a session on a network you do not operate at all — which Connectors cannot show you.
Connectors also works as a depot view. Filtered to a single location, it is how fleet operators track their own bays: `DE*SPI*E00012345*3` at 100% state of charge, power fallen to 0.72 kW, is a vehicle that has finished and can go. A bay still delivering a fraction of its rated power halfway through a shift is a van that will not be ready when its driver expects it.
Connectors updates as new data arrives from your charge boxes, not on a fixed refresh. That keeps it close to real time. Freshness still varies row by row, because each reading is only as current as that charge box's own OCPP reporting interval allows. Two connectors on the same page can differ.
An ongoing session is the live half of a session's life. Once it ends it becomes a charge detail record, immutable and ready for billing.
```mermaid theme={null}
flowchart LR
A("Driver authorises") --> B("Ongoing session")
B -->|"charge box stops, or Mark as Stopped"| C("Session finalised")
C --> D("Charge detail record")
D --> E("Priced for billing")
```
Live status tracking covers the first two steps. See [Sessions and CDRs](/components/charging/sessions-and-cdrs) for how the record itself is structured.
## Connectors
Connectors lists every connector available to you, including those at locations owned by customers beneath you in the hierarchy. To narrow the view to one customer's infrastructure, use [impersonation](/capabilities/account/impersonation).
### What each column shows
| Column | What it tells you |
| - | - |
| EVSE ID | The connector, with an icon for its type |
| Location / Customer | The site, and the customer that owns it |
| Authentication | What authorised the session, and the charge key's comment where it has one |
| Connectivity | Whether the connector's charge box is online or offline |
| Status | The connector's current live status |
| SoC | The state of charge of the connected vehicle's battery |
| Power | Power being delivered right now, in kW |
| Consumed | Energy delivered in the current session, in kWh |
| Info | The error code or message the charge box has sent over OCPP |
Read Connectivity and Status together. A faulted connector on an online charge box can tell you what is wrong; when the charge box itself is offline, the status beside it is the last one it managed to send.
The **Authentication** column is the fastest way to tell how a session was authorised:
| What the driver used | What appears |
| - | - |
| Spirii Go or a branded app with a payment method | `SpiriiGo-custId-123456` |
| An RFID charge key | `DK.SPI.0012345` |
| A virtual charge key | `DK.SPI.V0012345` |
| An app account with no payment method, charging at home | `Charging at home` |
| No authentication | `NoUID` |
| A Spirii POS payment terminal | `Payment Terminal` |
A charge key's comment appears alongside its identifier. A fleet charge key reads as `DK.SPI.0012345 - Fleet Car #10`, not as a bare identifier.
### Filtering the list
Status quick-filters sit across the top of the page:
| Filter | What it covers |
| - | - |
| All | Every connector |
| Available | Ready and unoccupied |
| Charging | Actively delivering |
| Faulted | Reporting a fault |
| Unavailable | Out of service |
| Idling | Preparing, Finishing, SuspendedEV, and SuspendedEVSE |
**Idling** groups four separate OCPP statuses under one filter: a connector plugged in but not yet drawing power, one that has finished and is waiting to be unplugged, and connectors paused by either the vehicle or the charge box. If you are reconciling against raw OCPP data, expect one Idling connector in Connect to be several different things underneath.
Alongside the quick-filters you can filter by location, selecting several at once, and by connector type, one at a time.
### Acting from the list
The menu at the end of each row carries the remote commands for both the charge box and the individual connector. You can act on what you are looking at without leaving the page.
## Ongoing sessions
Ongoing sessions lists sessions that have started and not yet finished. Two tabs split it by side of the network: My charging network for your chargers, My Drivers for your charge keys.
Ongoing sessions does not update on its own. If you are following a session while a driver is on the line, reload the page to see current figures.
### My charging network (CPO)
Sessions running on connectors you operate, whoever started them. This is the same population you would see filtered to Charging on the Connectors page, presented per session rather than per connector.
### My Drivers (eMSP)
Sessions your charge keys started, wherever they are charging — including on other operators' chargers over roaming.
| Column | What it tells you |
| - | - |
| Session ID | The session's identifier |
| Location / Owner | The site, and the customer that owns it |
| EVSE ID | The connector the vehicle is plugged into |
| Operator / Network | Who operates the site, and the network it belongs to |
| Authentication | What authorised the session, and its identifier |
| Start time | When the session began |
| Status | The EVSE's current status |
| Consumed | Energy delivered so far, in kWh |
### The charging curve
Selecting any session opens a modal with its charging curve and session data. The curve is how you tell a stalled session from one charging slowly by design. On another operator's chargers it reflects whatever data that operator sends, and can be sparser than a curve from your own charge box.
### Stopping a session
**Mark as Stopped**, at the end of a session's row, sends a stop command to the charge box. The charge box ends the session, and the platform finalises it, generates the charge detail record, and prices it. Only users with the Operator role can use it.
An eMSP can stop a session on another operator's charger the same way, which is the same action a driver takes from the app.
## Dependencies & limitations
* **Live figures are only as fresh as the hardware allows.** Connectors is bounded by each charge box's OCPP reporting interval. Ongoing sessions does not refresh on its own at all — reload it, or follow the connector on Connectors instead.
* **State of charge needs a DC charge box that receives and forwards it.** It appears only on DC charging, and only where the charge box gets the value from the vehicle and is configured to send it.
* **On another operator's chargers, you see what that operator sends.** Fewer fields, slower updates, and a sparser charging curve than a session on your own hardware.
* **Only the Operator role can stop a session.** Everyone else can watch a session but cannot use Mark as Stopped.
* **Connectors lists what you operate.** A partner with no chargers of their own sees an empty table.
## Related
If you are reconciling live figures against billing, start with the completed record rather than the live view.
How a session becomes an immutable, billable record.
The commands available from a connector's row menu.
What appears in the Authentication column, and how comments are set.
How sessions on other operators' networks reach your driver view.
# Remote commands
Source: https://docs.spirii.com/capabilities/operation-monitoring/remote-commands
The remote actions available on a connected charge box, when to reach for each, and where hardware limits what they can do.
Remote commands let you act on a connected charger from the platform, without sending anyone to the site: restarting it, starting or stopping a session, or freeing a stuck connector.
## Overview
Every command here acts on a charge box that's already **Online**: it travels over the charger's live OCPP connection, so a charger that's offline can't receive one. Getting a charger to that state is covered under [Charger activation](/capabilities/connection/charger-activation).
The commands fall into three groups.
Soft or hard reset, to apply configuration changes or recover an unresponsive unit.
Start or stop a charging session remotely.
Unlock a connector, or take one out of service for maintenance.
Each command is available two ways: run it by hand in **Spirii Connect**, or send it programmatically through the **Spirii API**. The behaviour is identical; the API reference for each is linked in its section below.
## Restarting a charger
It helps to separate two words the platform uses precisely. A **reset** is the command you send to tell a charger to restart. A **reboot** is the restart that actually happens, which the charger can also trigger itself, for instance after a firmware update or a power cycle.
There are two kinds of reset, and choosing between them is the main decision on this page.
Restarts only the charger's software while the hardware stays powered, taking roughly 30 to 60 seconds. Queued data and configuration are preserved.
Use it for applying configuration changes, planned maintenance, or troubleshooting a communication problem, including while drivers may be charging. A charger that responds to a configuration change with `RebootRequired` needs a soft reset to make the change take effect.
Forces a full hardware reboot, takes roughly one to three minutes, and carries a risk of losing data that hasn't been persisted. Keep it for a unit that's unresponsive, or one where a soft reset has already failed.
In many cases a hard reset also clears the fault messages the charge box was reporting. That takes away the error codes you would use to diagnose a problem that keeps coming back, so read the current faults off the charger before you send one.
Always try a soft reset first. A hard reset should be a last resort — it's more disruptive and can lose unpersisted data. In most cases either reset will interrupt and end any active charging session.
Most charge boxes keep their configuration, connector availability, local authorisation lists, and charging profiles across a reboot; active sessions, network connections, and cached data are cleared and re-established. Behaviour varies by model, so confirm against your hardware's documentation.
Send resets in Connect from the charge box, or through the API: [`reset`](/api-reference/chargeboxes-v2/performs-a-hard-or-soft-reset-on-a-charge-box) for either kind, or [`reboot`](/api-reference/chargeboxes-v2/reboots-a-charge-box-alias-for-soft-reset) as an alias for a soft reset.
## Managing sessions
### Remote start
A remote start begins a charging session without anyone touching the charger. You send the connector ID (say `DE*SPI*E00012345*1`) and an authorisation identifier, a [charge key](/components/access/charge-keys). The charger moves to `Preparing` straight away, even if no vehicle is plugged in yet. A `ConnectionTimeOut` sets how long it waits for a vehicle before returning to `Available`.
This is the only way to authorise a session without a physical action at the charger, such as tapping an RFID charge key or a payment card. It's what starts a session from a driver app or from Connect, and it's the tool your support staff reach for when helping a driver who can't get a session going on site.
### Remote stop
A remote stop ends a session that's already running: you send the `transactionId` of the active session, and the charger responds `Accepted` or `Rejected`. It's used less often than remote start, since unplugging the vehicle already stops a session. It earns its place when a session is stuck and your support staff need to force it to end.
Both commands trigger the charger's standard `StartTransaction` and `StopTransaction` messages, so billing and the session record stay accurate. Run them in Connect, or via [`start transaction`](/api-reference/evses-v2/requests-an-evse-to-start-a-transaction) and [`stop transaction`](/api-reference/evses-v2/requests-an-evse-to-stop-a-transaction) in the API.
## Managing connectors
### Unlock connector
An unlock command releases a connector's lock, sent against a specific connector ID. If a session is active on it, the charger completes that session first, then unlocks.
Whether it works depends on the hardware:
* It applies only to **AC sockets with electronic locks** — the case where a driver brings their own cable.
* On **CHAdeMO** connectors the charger controls the lock, so an unlock should succeed.
* On **Type 2 and CCS** connectors the *vehicle* controls the lock, so an unlock may not succeed.
Not every manufacturer implements this fully, so confirm the behaviour for your hardware. In practice it's for the case where a driver has released the cable at the car but it stays latched in the charger's socket, and your support staff try to free it. Run it in Connect, or via [`unlock connector`](/api-reference/evses-v2/requests-an-evse-to-unlock-a-connector) in the API.
### Change availability
Changing a connector's availability takes it out of service or brings it back, without affecting the rest of the charge box. Set a connector **Inoperative** to stop new sessions on it, for maintenance on a single connector while the others on the unit keep charging. Set it **Operative** to return it to service.
This changes the charger's real state, which also locks out a technician who needs to test the unit. To take a connector out of drivers' view while keeping it usable on site, set a [temporary EVSE status](/capabilities/operation-monitoring/temporary-evse-status) instead: eMSP apps and roaming partners report the unit as out of service, while the connector stays technically available for whoever is working on it.
Run it in Connect, or via [`change availability`](/api-reference/evses-v2/updates-the-availability-status-of-a-connector) in the API.
## Choosing a command
| Command | What it does | Reach for it when |
| - | - | - |
| Soft reset | Restarts the charger's software, preserving data and config | A config change needs to take effect, or a charger has a minor communication fault |
| Hard reset | Forces a full hardware reboot | The charger is unresponsive and a soft reset has failed |
| Remote start | Begins a session on a connector | Authorising a session without a physical tap, from an app, Connect, or support |
| Remote stop | Ends an active session | A session is stuck and needs to be forced to end |
| Unlock connector | Releases a connector's lock | A driver's cable is latched in an AC socket after they've unplugged the car |
| Change availability | Sets a connector Operative or Inoperative | Taking one connector out of service for maintenance |
## Dependencies & limitations
* **The charger must be online.** Commands travel over the live OCPP connection; a charger that isn't connected can't act on them.
* **Resets end active sessions.** In most cases a soft or hard reset interrupts and ends whatever session is running.
* **Hard reset can lose data.** Unpersisted data may not survive a hard reset, which is why it's a last resort.
* **Unlock depends on the connector.** It works on AC sockets with electronic locks; on Type 2 and CCS the vehicle holds the lock, so it may not succeed, and support varies by manufacturer.
* **These act on the charger's real state.** To change only the status a driver sees in an app, without touching the charger, use [Temporary EVSE status](/capabilities/operation-monitoring/temporary-evse-status) instead.
## Related
The unit these commands act on, and where its logs and connection history live.
The connector level that session and connector commands target.
How a charger gets online in the first place — the prerequisite for every command here.
Override the status drivers see in apps, without changing the charger's real state.
# Service level agreements
Source: https://docs.spirii.com/capabilities/operation-monitoring/service-level-agreements
Tell your team which sites carry a tighter commitment.
Service level agreements (SLAs) let you record the response times you have agreed with your customers and bind them to the locations they cover, so anyone working an issue can see which sites take priority.
## Overview
Not every location deserves the same response. A high-traffic DC hub losing a charge box costs more per hour than a quiet suburban AC site, and your agreements with your customers usually reflect that.
An SLA in Spirii Connect captures one of those agreements: a name, the response times you have committed to, and who to call for on-site work. Every location is bound to one.
You manage SLAs in Connect under **Operations → Service Level Agreements**, which is available to users with the Operator role.
These are your agreements with your own customers. Any service commitments acquired from Spirii's support teams are not displayed or configured here.
An SLA documents the priority attached to a location and the contacts behind it. Connect keeps the response times visible to whoever is working an issue; you measure performance against them in your own service desk.
## How it works
### What an SLA records
| Field | What it does | Example |
| - | - | - |
| Name | Identifies the SLA in the list and on bound locations | `Critical sites` |
| Description | Context for whoever reads it later | `DC hubs on the motorway corridor` |
| 1st level resolution time | Your first-response deadline. Mandatory | `4 hours` |
| 2nd level resolution time | Your escalation deadline. Mandatory | `8 hours` |
| Restrict to weekdays | Set per level, so weekends stop the clock | `Off` |
| Installer or OEM contact | Free text for whoever attends on site | `Nord Elektro, +49 89 1234 5678` |
| Default | Applies this SLA to new locations. One SLA at a time | `On` |
### The two resolution levels
Both levels are mandatory, and each carries its own **Restrict to weekdays** option, so a weekday-only first level can sit alongside a second level that counts weekends.
The labels follow a conventional support escalation:
The initial response: an agent picking up the report and attempting remote diagnosis, including sending commands to the charge box.
The deeper technical pass for issues that survive the first, reading OCPP logs and interrogating platform data.
Conventionally third line, and an SLA has no deadline field for it. Instead it carries the installer or OEM contact, so whoever is working the issue knows who to call.
How you define each level, and whether you treat the two deadlines as cumulative or independent, is yours to decide. Connect stores both figures as you enter them and does not add them together.
### Binding SLAs to locations
Mark one SLA as **Default** and every location created afterwards is bound to it automatically. Marking a different SLA as default moves that flag, but it does not reassign locations that were already bound to the old one.
For locations that need something other than the default, bind them manually in either direction:
* From the SLA's **Locations** tab, search for locations and bind them in bulk
* From a location's edit screen, pick the SLA at the bottom of the page
A location bound to anything other than the default carries a flag. Whoever picks up an issue sees the exception rather than having to remember it.
### What your customers see
Anyone viewing a location can click its SLA name to open a modal showing the response times and details. That includes your customers, on the locations they own, so the commitment is visible to the party you made it to. The Service Level Agreements page itself, where SLAs are created and edited, remains operator-only.
### A worked example
`Rheinstrom GmbH` runs a mixed estate. It creates an SLA named `Standard`, with a 24-hour first level and a 48-hour second level, both restricted to weekdays, and marks it as default. Every new location it adds is bound to `Standard` without anyone touching it.
`Munich DC Hub` is different: high-traffic DC, and Rheinstrom has committed to a four-hour response including weekends. So Rheinstrom creates a second SLA named `Critical sites` with 4-hour and 8-hour levels, weekday restriction off, and the site installer's number in the contact field. From that SLA's Locations tab, it binds `Munich DC Hub`.
An agent opening `Munich DC Hub` months later sees the flag, clicks the SLA name, and has the four-hour commitment and the installer's number in front of them.
## When to use it
**One default, and specials only where the commitment genuinely differs.** The flag on a non-default location is only useful while non-default locations are rare. An estate where half the sites carry bespoke SLAs gives an agent nothing to notice, and each extra SLA is another record to keep aligned with the contract behind it.
**Create the default before you start adding locations.** Locations inherit the default at creation, so setting it up first saves binding them by hand afterwards.
## Dependencies & limitations
* **SLAs document; your service desk measures.** An SLA records the commitment and the contacts, and makes them visible on the locations it covers. Performance against the response times is tracked in your own service desk.
* **Operators only.** Creating and editing SLAs requires the Operator role. Customers can view an SLA on their own locations but cannot reach the Service Level Agreements page.
* **Changing the default is not retroactive.** Locations bound to a previous default stay bound to it.
* **Deleting an SLA leaves locations without one.** Locations bound to a deleted SLA end up with no SLA rather than falling back to the default, so rebind them before you delete it.
* **One SLA per location.** A location carries a single SLA at a time.
* **Contact details are free text.** The installer or OEM contact is not validated and is not linked to a contact record elsewhere in the platform.
## Related
To bind an SLA to a site, use the SLA's **Locations** tab, or pick it from the location's edit screen.
Where a location's SLA is bound, alongside its other settings.
The customers your agreements are with, and the hierarchy they sit in.
What a location is, and what else it anchors.
The remote diagnosis a first-level response usually starts with.
# Temporary EVSE status
Source: https://docs.spirii.com/capabilities/operation-monitoring/temporary-evse-status
Control the status a charger shows to drivers and roaming partners.
A temporary EVSE status overrides the status a charger shows to drivers and roaming partners, while leaving the charger's real state untouched. You can show a unit as out of service in every app and still keep it running for a technician to work on.
## Overview
Every EVSE has two statuses that normally agree. Its **actual status** is what the charger reports over OCPP, such as available or charging. Its **displayed status** is what drivers see in eMSP apps. A temporary EVSE status lets you set the displayed status on its own, for a period you choose, without changing what the charger is really doing.
This solves something the standard OCPP controls can't. Setting an EVSE unavailable over OCPP (the [change availability command](/capabilities/operation-monitoring/remote-commands#change-availability)) takes it genuinely offline, which locks out the technician who needs to test it. A temporary status changes only what drivers see: the app reports the unit as out of service while the charger stays fully operational for on-site work.
You set a status one of two ways: an operator sets **Maintenance** or **Commissioning** by hand, and an external system sets **Blocked** or **Reserved** through the API.
## How it works
You apply a temporary status to a single EVSE, choosing the status and an active period: a start, and an optional end. It takes effect at the start and clears automatically at the end; leave the end open and it holds until you remove it. Clearing it (at the end of the period, or with a [`remove`](/api-reference/temporary-evse-statuses-v2/remove-a-temporary-evse-status) call before then) reverts the displayed status to the charger's actual state.
Setting a temporary status takes the same access as remote commands. Any [role](/capabilities/account/roles) that can run those can set one.
Whatever status you set is translated into each channel's own vocabulary before it reaches a driver. The [table below](#how-the-status-appears-to-drivers) shows exactly what they see.
In Spirii Connect, the temporary status sits alongside the actual status in the charge box list. You watch the real one while drivers see the override. During a maintenance test you can confirm the unit is charging cleanly even as every app reports it out of service.
For example, you set EVSE `DE*SPI*E00012345` to **Maintenance** for a two-hour service window. In Spirii Go and to roaming partners the unit shows as out of service. No driver arrives expecting to charge, and your technician runs test sessions on it throughout.
### Operator-set statuses: Maintenance and Commissioning
These are the statuses an operator controls directly, in Connect or through the API.
Covers a unit being serviced or tested. Drivers see it as out of service and none turn up expecting to charge, while it stays live for the technician.
Covers a newly installed unit that isn't ready for drivers yet. It shows as out of service (or *Planned* to OCPI partners), keeping it off drivers' radar until you publish it properly.
In Connect, open the EVSE from its charge box on the location and set the status from the EVSE's menu, with a start date and an optional end. Through the API, [`create`](/api-reference/temporary-evse-statuses-v2/create-a-new-temporary-evse-status) the status against the EVSE ID.
### System-driven statuses: Blocked and Reserved
These come in through the API, letting a platform in your wider ecosystem drive them in real time.
For a parking-sensor integration. When a sensor detects a vehicle occupying the bay in front of the charger, it sets the EVSE blocked, and drivers see the unit as occupied.
For a booking or reservation platform. When a charger is reserved ahead of time, the platform sets it reserved, and drivers see it as reserved.
Both use the same [`create`](/api-reference/temporary-evse-statuses-v2/create-a-new-temporary-evse-status) call as the operator statuses. The difference is that a system, rather than a person, sets them.
An EVSE carries one temporary status at a time. Setting a new one replaces whatever is already there, so a status arriving from an external system overwrites one an operator set by hand, and the reverse. Plan for that where a booking or sensor integration runs against sites your technicians also work on.
## How the status appears to drivers
Each app, hub, and protocol carries its own status vocabulary, so the status you set is mapped to the nearest equivalent on each channel. This is what a driver actually sees:
| Temporary status | Spirii Go & branded apps | Hubject (OICP) | OCPI roaming partners |
| - | - | - | - |
| Maintenance | Out of Service | Out of Service | Inoperative |
| Commissioning | Out of Service | Out of Service | Planned |
| Blocked | Occupied | Occupied | Blocked |
| Reserved | Occupied | Reserved | Reserved |
## Dependencies & limitations
* **Displayed status only.** A temporary status never changes the charger's real state or interrupts an active session — the charger keeps reporting its true status, and you keep seeing it in Connect. To change the real state rather than the displayed one, use the [change availability command](/capabilities/operation-monitoring/remote-commands#change-availability) instead.
* **One status per EVSE.** You set it per EVSE, never across a whole charge box or location, and a new status replaces any existing one on that EVSE.
* **Blocked and Reserved are API-only.** Operators set Maintenance and Commissioning in Connect or the API; Blocked and Reserved arrive through the API, typically from an external system.
* **Translation is fixed per channel.** You choose the Spirii status; how it appears on each channel follows the table above and isn't separately configurable.
## Related
The object a temporary status targets, and where its real status lives.
The channels a temporary status is translated across before it reaches a driver.
The change availability command, for when you need to change a charger's real operational state rather than its displayed one.
Create, update, and clear statuses programmatically.
# In-app payments
Source: https://docs.spirii.com/capabilities/payments/in-app-payments
The default payment channel for app users, with Spirii as the merchant on every session.
In-app payments let drivers start a session and pay for it without a physical card or a separate terminal. Spirii is the Merchant of Record for every one of them, handling processing, VAT, and digital receipts, so what reaches you is a monthly payout rather than an acquiring relationship to run.
## Overview
A monthly payout for every app session on your network. Spirii holds the acquiring agreement, carries the PCI obligations, and handles disputes and refunds.
The same payment flow in your own app and your own brand, running on Spirii's payment infrastructure. You publish the app; the payment stack is already built.
The channel is on by default wherever drivers use [Spirii Go or your branded app](/capabilities/driver-experience/spirii-go-and-branded-apps), and needs nothing on the charger beyond what is already there. Registration is not a barrier either: a driver can charge as a guest, starting and paying for a session without creating an account.
## How it works
The driver opens Spirii Go or your branded app and starts a session on one of your chargers.
A hold goes on the driver's card or wallet, sized to cover a typical session at that charger type and tariff.
When charging stops, Spirii captures the actual amount from the energy consumed and the tariff at that location.
A digital receipt lands in the app immediately, itemising the session and the VAT. See [Receipts](/capabilities/compliance/receipts) for what it carries and how a driver retrieves one later.
App revenue is paid the following month by self-billing invoice, net of platform and payment fees.
That last step works because of who the merchant is: Spirii buys the energy from you and resells it to the driver at the moment of the transaction. [Billing and payout flows](/capabilities/billing-payouts/billing-and-payout-flows) sets out what that means for VAT, chargebacks, and your invoice.
## Supported payment methods
In-app payments run on Stripe, which is what gives the app its range of methods.
* All major card issuers such as Visa, Mastercard, American Express and more
* Apple Pay
* Google Pay
* SEPA Direct Debit, and iDEAL, which settles over SEPA
Drivers stay in the app to pay. Where a card needs Strong Customer Authentication, the 3-D Secure challenge runs in a frame inside the app rather than sending the driver to a browser. iDEAL is the exception: it hands the driver to their bank to confirm, then returns them to the app.
## Pre-authorisation and capture
EV charging is open-ended — at plug-in, neither the driver nor the platform knows how much energy the session will take. Spirii places a hold when the session starts, then captures the exact amount when it ends. Any difference is released immediately, with no separate refund. If a session turns out more expensive than the hold, Spirii raises the hold by incremental authorisation rather than taking a second payment.
A failed pre-authorisation stops the session before it starts, and the driver is prompted for a different payment method. A failed capture after the session has completed is retried automatically over the following days.
See [Pre-authorisation and capture](/capabilities/payments/pre-auth-capture) for how the hold is sized, adjusted, and reused.
## Dependencies & limitations
* **The driver needs the app on their phone.** Guest charging removes the need to register, but not the need to have downloaded Spirii Go or your branded app. For a driver who arrives with neither, [in-person payments](/capabilities/payments/in-person-payments) take payment at the charger itself.
* **You cannot bring your own acquiring.** Spirii is the merchant on every app session. There is no bring-your-own-PSP equivalent to the PAAS mode offered on payment terminals, so if holding the acquiring agreement matters to you, that route exists on terminals only.
* **Not every app session earns a payout.** Sessions under 0,2 kWh, sessions running longer than seven days, and free or voucher-funded charging are excluded from the self-billing invoice. The specification file accompanying each payout gives the reason per session. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **App revenue pays out the following month.** Inbound roaming revenue pays in the same month Spirii invoices the roaming partner; app revenue does not.
* **The methods on offer vary by market.** Cards, Apple Pay, and Google Pay are broadly available. Which local methods a driver sees depends on where they are charging.
## Related
The channel that covers the drivers this one cannot is in-person payments.
Contactless payment at the charger, for drivers with no app and no account.
How Spirii authorises and captures payment for open-ended sessions.
How Spirii collects from drivers and pays you out for app sessions.
What an app receipt carries, and how a driver finds one after the fact.
# In-person payments
Source: https://docs.spirii.com/capabilities/payments/in-person-payments
Three ways to put a payment terminal on your chargers, and what each one asks of you.
In-person payments let any driver pay at the charger by tapping a card or phone, with no app download and no account. Payment happens on a terminal at the point of charging, and Spirii supports three ways of integrating one. They differ in who supplies the terminal software and who owns what the driver sees on screen.
## Overview
Spirii supplies the point-of-sale (POS) software, and optionally the hardware and the acquiring agreement too.
The charger maker's own terminal and driver screen, with Spirii as the back office behind it.
A self-contained cloud POS from a payment provider, connected to Spirii over OCPI.
In all three, you manage terminals, locations, chargers, and tariffs in the Spirii platform, and terminal revenue reaches you through Spirii's billing and payout. Each terminal is also a record in Spirii Connect that names its merchant and the charge boxes it serves. See [Payment terminals](/components/commercial/payment-terminals) for that record and what it controls.
## Choosing an approach
| Approach | Use it when | Who owns the driver-facing flow |
| - | - | - |
| Spirii POS | You want one supplier for the terminal, the screen, and the money, or you want drivers to stop sessions at the terminal and use their charge keys there too | Spirii |
| Charger manufacturer POS | Your charger maker already integrates a terminal locally, or you want a specific terminal they support | The manufacturer |
| Third-party POS over OCPI | Your payment provider runs its own cloud POS that you want to keep | The provider |
Whoever owns the driver-facing flow also carries AFIR and Eichrecht compliance for it: the price on screen, the receipt, and the ad-hoc payment experience. That is the part you hand over when you run someone else's POS. The wider obligations on a public site, including price transparency and infrastructure reporting, stay with you as the operator either way. See [Location configuration](/capabilities/connection/location-configuration).
## Spirii POS
Spirii's own integration is built around the Payter Apollo terminal. It connects to the Spirii platform over the Spirii POS application and talks to the charger over OCPP, so the terminal and charger work as one unit.
You can take it complete, or bring your own acquiring.
Spirii provides hardware, POS software, terminal management, and acquiring. You receive a monthly payout for all terminal revenue, and Spirii is the Merchant of Record.
Spirii provides the POS software and optionally terminal management. You bring your own acquiring agreement with a payment service provider (PSP) and stay the Merchant of Record.
Turnkey and PAAS are the standard setups, but hardware and acquiring can also be arranged separately: a Payter Apollo you source yourself, running Spirii POS on Spirii's Merchant ID, or Spirii-supplied hardware on your own acquiring agreement. Who handles what in the table below depends on the split, so agree it with your account manager.
### What's included
| Component | Turnkey | PAAS |
| - | - | - |
| Terminal hardware (Payter Apollo) | Spirii supplies | You or the charger manufacturer supplies |
| POS software | Spirii POS | Spirii POS or a third-party POS |
| Terminal registration and management | Spirii | You or the terminal manufacturer |
| SIM cards and connectivity | Spirii | Terminal manufacturer or LAN |
| Acquiring agreement (Merchant ID) | Spirii | Your own PSP |
| PCI-DSS compliance | Spirii, as service provider | You, as merchant |
| VAT reporting | Spirii | You |
| Dispute and refund management | Spirii | You |
### Charge keys at the terminal
The Payter Apollo reads RFID charge keys as well as cards and phones, so drivers can tap their charge key on the terminal to start a session. That matters most on chargers with no RFID reader of their own: one terminal serves drive-up drivers paying by card and fleet drivers on their charge keys.
A session started this way is authorised and billed exactly as if the driver had tapped the charge key on the charger itself. The same [charge key authentication](/capabilities/access/charge-key-authentication) rules decide whether it's accepted, and the session is invoiced through [charge key billing](/capabilities/billing-payouts/charge-key-billing) rather than paid at the terminal. This works in turnkey and PAAS, including on a terminal that serves several charge boxes.
### Stopping a session from the terminal
Drivers can stop a session from the Spirii POS terminal screen, which sends the stop command to the charger over the OCPP link. On a public site that matters more than it sounds: a driver who left their phone in the car, or who wants to see charging confirmed as ended, has somewhere to go that isn't your support line.
A driver who started with a charge key stops by tapping the same charge key. The terminal finds their active session, asks them to confirm, and stops it. It shows no receipt, because charge key consumption is invoiced. See [Receipts](/capabilities/compliance/receipts).
### Set up
Going live with a Spirii POS terminal takes four things. Two of them depend on a third party, so start those early.
* **The hardware.** A Payter Apollo unit, supplied by Spirii under turnkey, or by you or your charger manufacturer under PAAS.
* **A Merchant ID.** One per location. Spirii requests it from the PSP under turnkey; under PAAS you bring your own.
* **Registration with Payter.** Through Connect or the Payter portal.
* **The terminal record in Connect,** linked to the charge box or boxes it takes payment for.
If drivers will tap charge keys at the terminal, it also has to be set to read them. Check with Spirii that this is switched on for your terminals.
See [Payment terminal with Spirii POS](/guides/payment-terminal-setup) for the order and the detail.
## Charger manufacturer POS
Spirii integrates with a range of charger manufacturers. The manufacturer owns the terminal and the driver-facing experience, and Spirii runs as the POS back office behind it. Use this where the charger and terminal are already integrated locally, or where you want a specific terminal the manufacturer supports.
Settings reach the terminal through the charge box. You set the basics in Connect, price among them, and they are pushed as charge box configuration over OCPP. The manufacturer's POS may also have a backend of its own that Spirii has no part in, so some of what a driver sees is configured somewhere you do not manage through Spirii.
How much comes back varies a lot from model to model. A terminal and POS can sit on the same charging hardware as Spirii and still report very little: a session can arrive without a total price, or without the detail behind it. Establish what a given model actually reports before you standardise on it.
The manufacturer handles AFIR and Eichrecht compliance for what the driver sees.
## Third-party POS over OCPI
Spirii also integrates with third-party POS providers over OCPI. These are self-contained cloud solutions, usually built by payment providers themselves.
Spirii exchanges location, charger, and tariff information with the provider over OCPI, and that same link starts and stops charging sessions. The provider handles AFIR and Eichrecht compliance for the payment flow.
## Dependencies & limitations
* **Spirii POS runs on the Payter Apollo.** Spirii's own integration is built for that unit — a different terminal means taking the charger manufacturer or third-party route instead.
* **Spirii's Merchant ID needs a Payter Apollo running Spirii POS.** A terminal on a charger manufacturer's POS or a third-party POS uses your own acquiring.
* **A charge key at the terminal follows the charger's rules.** The terminal adds no access rules of its own. Whether a charge key is accepted, and how its session is billed, is decided exactly as for a tap at the charger.
* **A Merchant ID is needed per location, not per account.** Spirii requests it from the PSP under turnkey, but the PSP's own checks set the pace, which is why it is worth starting before the hardware arrives.
* **Under PAAS, terminal revenue does not come through Spirii.** Funds arrive directly from your PSP, and those sessions are excluded from your Spirii self-billing invoice. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **With another provider's POS, the driver-facing layer is theirs.** The screen, the receipt, and compliance for the payment flow sit with them, and how much session detail reaches Spirii depends on the integration. The terminal is still managed in Connect, and its revenue still flows through Spirii's billing and payout.
* **Third-party terminal sessions produce a statement, not a receipt.** That provider took the payment, so the document Spirii produces records the session without VAT details. See [Receipts](/capabilities/compliance/receipts).
## Related
For a driver who does have your app, in-app payments cover the same site without hardware.
The terminal record in Connect, its merchant, and the charge boxes it serves.
Register, configure, and go live with a terminal.
Payment through Spirii Go or your branded app, including guest charging.
How terminal revenue reaches you, in turnkey and in PAAS.
# Payment flows
Source: https://docs.spirii.com/capabilities/payments/payment-flows
How Spirii handles money — from a driver tapping a terminal to a CPO receiving their monthly payout.
Spirii sits between the driver's payment and your bank account. From the moment a driver pays to the moment revenue lands with you, Spirii manages acquiring, VAT, settlement, and payouts.
```mermaid theme={null}
flowchart LR
A("Driver (app)") --> S("Spirii platform")
B("Driver (terminal)") --> S
C("Driver (charge key)") --> S
D("Roaming partner") --> S
S --> E("CPO / site owner payout")
S --> F("Fleet monthly invoice")
S --> G("Employee reimbursement")
```
## The four payment channels
Payments on the Spirii platform work across four channels. Each brings drivers different payment options, and you different operational requirements.
Drivers pay through the Spirii app or your branded app. Spirii handles acquiring, VAT, and digital receipts as Merchant of Record.
Contactless card, Apple Pay, and Google Pay at the charger. Under turnkey, Spirii supplies the terminal, POS software, and acquiring; under PAAS you bring your own terminal and acquirer. The two can also be split.
Fleet drivers tap an RFID card or virtual charge key. With Full Service billing, Spirii consolidates all sessions into a single monthly invoice to the fleet company.
Drivers from other networks charge on your stations, or your drivers charge on other networks. Spirii handles the cross-network invoicing and settlement.
### Choosing a channel
| Channel | Enable it when | What it needs |
| - | - | - |
| In-app payments | Always. It is the default for anyone using Spirii Go or your branded app | Nothing beyond the charger |
| In-person payments | A high-traffic public site (motorway, retail car park, destination charging) draws drivers who have no charging app | A Payter Apollo terminal, and a Merchant ID: Spirii's under turnkey, your own under PAAS |
| Charge key billing | You serve fleet or corporate customers | An RFID reader on the charger, and charge keys issued by the employer |
| Roaming | You want reach beyond your own drivers | Nothing beyond the charger, plus a roaming tariff that covers your costs and margin |
Most public sites run several at once. For the full mechanics per channel (who the merchant is, who gets invoiced, when payouts land), see [Billing and payout flows](/capabilities/billing-payouts/billing-and-payout-flows).
## Where you sit in the flow
Which side of the platform you are on decides whether money arrives or leaves.
### As a CPO
You receive a monthly payout by self-billing invoice, covering every session across the channels you have enabled: app, terminal, charge key, and roaming. Where you share revenue with site owners, Spirii splits the payout and routes it to each party directly.
### As a fleet operator or eMSP
Your company receives one consolidated bill for all charging by your drivers, both on the Spirii network and across roaming partners. Where your employees charge at home, Spirii pays the reimbursement straight to their bank accounts.
## Dependencies & limitations
* **Spirii is not always the Merchant of Record.** It is on in-app and roaming, and on in-person under turnkey. Under in-person PAAS you keep your own acquiring agreement and stay the merchant, and on charge key billing it follows the billing service level.
* **Two of the four channels need hardware on the charger.** In-person needs a Payter Apollo terminal; charge key billing needs an RFID reader. In-app and roaming run on infrastructure you already have.
* **Only in-person payments serve a driver with nothing installed.** In-app does not need an account, because a driver can charge as a guest, but it does need Spirii Go or your branded app on their phone. Charge key billing needs a fleet or eMSP account, and roaming an account with the driver's own eMSP.
* **Spirii invoices your fleet customers only at Full Service.** Under Invoice Data Service you invoice them yourself from data Spirii aggregates; under No service Spirii records the session and settles roaming only.
* **Payout timing is not uniform.** App, terminal, and charge key revenue pays out the following month. Roaming pays in the same month the roaming partner is invoiced.
* **In-person needs a Merchant ID per location.** Spirii requests it from the PSP under turnkey, or you supply your own under PAAS.
## Related
How money moves between drivers, Spirii, and you — from payment to payout.
How Spirii distributes revenue to CPOs, site owners, and subsidiaries.
# Pre-authorisation and capture
Source: https://docs.spirii.com/capabilities/payments/pre-auth-capture
The two-step payment model behind every app and terminal session on the platform.
Spirii reserves an estimated amount on the driver's payment method when a session starts, then charges the real one when it ends. Nobody knows the price at plug-in, which is why payment happens in two steps.
## Overview
```mermaid theme={null}
flowchart TD
A("Session starts") --> B("Reservation placed")
B --> C("Session runs")
C -->|"cost exceeds the reservation"| D("Reservation raised")
D --> C
C --> E("Session ends")
E --> F("Exact amount captured, remainder released")
```
Every session on the platform is paid for this way, whether the driver started it in an app or tapped a card at a terminal. The reservation goes on at the start and the charge at the end, with the difference released rather than refunded.
Doing it in that order means a card that is going to decline declines before any energy reaches the car. It also means a driver's statement shows a reservation for one amount and a charge for another.
## How it works
Two of these steps run on every session. The other two cover a session that costs more than expected, and one that never starts.
When a driver starts a session in Spirii Go or a branded app, Spirii pre-authorises their card for an estimated amount. The money is reserved, not charged.
The amount is calculated per session from the location's tariff. Locations that are neither public nor roaming-enabled use a lower multiplier, so a workplace site reserves less than a public one on the same tariff.
On a payment terminal, the PSP places the reservation instead. See [Terminal sessions](#terminal-sessions).
When the session ends, Spirii captures the exact amount from the energy consumed and the tariff. The reservation is released and replaced by the final charge.
Where the final amount is lower than the reservation, the difference is released immediately. No separate refund is needed.
If a session runs past what the reservation covers, Spirii raises the existing one by incremental authorisation rather than opening a second.
One reservation, one charge — however long the session turns out to be.
Spirii keeps the reserved funds when charging fails to start, and reuses them if another session is attempted on the same payment method. A driver who meets a charger with poor connectivity can move to the next one.
Without this, every failed attempt would leave its own reservation sitting on the card.
## When a payment fails
Where the failure lands decides what happens next, and the dividing line is whether the energy has been delivered yet.
The session does not start. Insufficient funds or a declined card means no reservation, and no reservation means no charging.
The driver sees an error and is prompted for a different payment method.
The energy has already been delivered, so Spirii retries the charge automatically, a few times over the following days. A card expiring between the start and end of a long session is the common cause.
If the retries are exhausted, the session is marked as unpaid in Spirii Connect.
## Terminal sessions
On payment terminal sessions the reservation is placed by the payment service provider (PSP) rather than by Spirii: Worldline, Elavon, Stripe, or another, depending on the setup. The terminal shows the driver the pre-authorisation amount before they confirm with a tap or a PIN.
Capture follows the same logic as an app session. The exact amount is taken when the session ends, triggered by the OCPP stop signal from the charger. Terminals running Spirii's POS integration also reuse reservations, so a charger malfunction does not leave a driver with several reservations against their bank account.
## Dependencies & limitations
* **The reservation is an estimate, and the driver sees it.** It is sized from the location's tariff, so it rarely matches the final price. A driver checking their banking app mid-session sees the reservation, not what they will pay.
* **A session running longer than seven days is not paid out.** Revenue cannot be guaranteed on a reservation held that long, so those sessions are excluded from your self-billing invoice. See [Understanding your payout](/capabilities/billing-payouts/payouts).
* **On terminal sessions, the PSP owns the reservation.** Spirii captures against it, but the pre-authorisation itself follows that provider's rules rather than Spirii's.
* **Reservation reuse covers app and Spirii POS sessions.** A terminal running a charger manufacturer's POS or a third-party POS handles its own reservations, so the behaviour there is that provider's.
## Related
How app-based payment sessions work from driver to payout.
How terminal sessions handle pre-auth and capture.
The session and CDR data that drives billing and payment status.
# Pricing options and logic
Source: https://docs.spirii.com/capabilities/pricing/pricing-options-and-logic
Define the price and conditions for drivers charging on your infrastructure.
Pricing options and logic is how you build what a driver pays to charge: a fixed or dynamic base price, conditional fees layered on top, and a separate price for roaming.
## Overview
A tariff composes a price from two parts: a **base fee** that always applies, and optional **conditional fees** that take over when their conditions are met.
You build it once and apply it to as many locations as you like.
Separately, you set a **roaming tariff**: the price external networks are billed when their drivers charge at your locations.
## Set up
Build tariffs under **Tariffs** in Spirii Connect: set the name, currency, and base fee, add any conditional fees, then bind the tariff to your locations. Set the roaming tariff separately, on each location. A tariff applies the moment it's bound; a roaming tariff change applies at the next midnight.
## How it works
### The base fee
Every tariff starts with a base fee, in one of two modes:
A set price per kWh or per minute that doesn't change.
The hourly spot price for a power grid zone, with your markup on top.
Fixed keeps the price predictable; dynamic lets it track your wholesale electricity cost through the day.
For dynamic, a minimum fee acts as the floor and the fallback if spot data drops too low or goes missing.
### Conditional fees
On top of the base, you can add conditional fees that apply only when their conditions are met:
Per kWh. On a dynamic tariff, this is the markup over spot.
Per minute, for the duration of the session.
Per session, a one-time charge.
Each fee can be limited to specific **timeslots and days**, or set to apply only **after a session has run** for a set time, counting both active charging and idle time once the car is full.
### How fees resolve
When fees overlap, two rules keep the price predictable:
* Fees are read **top to bottom**, so their order matters. A fee with a longer delay should sit above one with a shorter delay, since the shorter delay is reached first.
* If two fees of the **same type** have overlapping conditions, only the top-most applies; a session is never charged twice for the same thing.
Every price is shown to the driver gross, including VAT.
## Common pricing patterns
A few patterns cover most needs:
Set the base fee to your lowest (night) rate, then add energy fees for the daytime and peak periods using timeslots, mirroring how electricity costs rise and fall through the day.
Add a time fee that switches on after, say, 180 minutes, so a driver who's finished charging is nudged to move on. Limit it to the hours where it matters; the driver is warned in the app before it starts.
Stack time fees with increasing apply-after delays (free for the first hour, a per-minute fee after 60 minutes, and a higher one after 120) to keep a busy site turning over.
Add a flat fee, at the start or after a delay, where a one-time charge fits the model.
## Roaming pricing
The price you set toward external networks is separate from your tariff, and simpler. You set a **roaming tariff** per location, when editing that location in Connect: a single flat rate per kWh, chosen from a pre-made list rather than built from scratch:
* You enter it **gross** (including VAT for the location's country) so it's comparable with your tariff, but eMSPs are billed the **net** amount. A 1.00 € roaming tariff in a country with 25% VAT reaches the eMSP as 0.80 €.
* Changes take effect at **midnight**; until then the current roaming tariff stands. Selecting **No Roaming** turns it off for the location.
* Roaming partners add their own margin on top, so a driver arriving over roaming may see a higher price than your roaming tariff.
## Dependencies & limitations
* **Tariffs apply within Spirii's own surfaces.** Spirii Go, branded apps, Spirii charge keys, and Spirii POS. External networks receive the roaming tariff instead.
* **The roaming tariff is a flat per-kWh price only**, billed net to eMSPs, effective at midnight, with partner margin added on top.
## Related
The tariff object this builds on.
How the roaming tariff reaches external networks.
Tariffs and roaming tariffs are applied per location.
Where the price a tariff produced is recorded.
# Dashboard
Source: https://docs.spirii.com/capabilities/reporting-analytics/dashboard
See how your network performed, and identify where to optimise it.
The Dashboard is the first page you land on in Spirii Connect. It reports what the chargers you operate delivered over a period you choose, with each figure set against the period before it.
## Overview
Every metric on the page answers a question you would otherwise export data to answer: how much did we charge, what did it earn, how busy were we, and was anything broken.
The figures cover the chargers you operate, and three filters decide which of them are in scope.
When you need to go below what the page shows, [export it as a CSV](/capabilities/reporting-analytics/exports#dashboard-exports) — one row per connector per day, on whatever filters and time range you have set.
## Filters and time range
Three controls scope everything the page reports.
Defaults to the last seven days. Yesterday, 30 days, and a custom range are also available.
Narrows the page to one customer's locations, including those owned by its child customers.
Narrows to a single location.
Each period metric also shows how it compares with the immediately preceding window of the same length, so a seven-day view is measured against the seven days before it.
The Dashboard follows the [customer hierarchy](/capabilities/account/customer-management#the-customer-hierarchy), and [impersonation](/capabilities/account/impersonation) scopes it the same way it scopes the rest of Connect.
## Live cards
Two cards ignore the time range, because they report the present rather than a period.
Counts **connectors**, not charge boxes, split across offline, charging, available, and idle. A charge box with two connectors that drops offline therefore adds two to the offline count.
Plots every location in your network, including locations still pending.
## Period metrics
Everything else on the page is calculated over the selected range. Each card is defined below, in the order it appears.
The total value of all charging sessions in the period, excluding VAT.
This is transaction value rather than revenue. It does not account for the commercial agreements you hold with Spirii or with your operator, so it will not match the figure on your invoice. Read it as what your chargers billed, before anything is settled.
An estimate of the emissions avoided by charging electrically instead of burning fuel, calculated from consumption:
**Estimated CO₂ saved (tonnes) = total kWh × 5.5 × 0.000150**
The two constants are the distance an average EV covers per kWh (5.5 km) and the emissions of a comparable combustion car (150 g/km, or 0.000150 tonnes/km). Both are published figures from the Danish Committee on Climate Change, 2018.
The estimate is gross. It describes displaced fuel rather than a net carbon position, because it does not subtract the emissions of the electricity used to charge.
That suits awareness, comparison, and stakeholder communication. For lifecycle carbon accounting or a Scope 1–3 audit, take your consumption data to a sustainability advisor.
One interactive graph carrying five figures for the period.
| Figure | What it counts |
| - | - |
| Active users | Unique authorisation charge keys that completed a session |
| Charging sessions | The number of charge detail records (CDRs) |
| Consumed | Total energy delivered, in MWh |
| Avg. consumption | Energy delivered per session |
| Avg. duration | Average time a vehicle was connected per session, charging and idle combined |
Active users counts **authorisation charge keys**, not people: the RFID card, app charge key, or free-vending tag the session was started with. One driver carrying two RFID cards therefore counts as two active users, and one fleet card shared by six drivers counts as one.
Roaming drivers usually resolve to individual charge keys. Sessions with no individual identity behind them are grouped instead, because they all arrive carrying the same charge key value: everything authorised through a payment terminal counts as one user, and everything with no authentication counts as one user. A site taking five hundred contactless payments in a week therefore contributes one active user, not five hundred.
A session only counts if it completed and delivered energy, and if it both started and ended inside the selected range. A session running from 23:40 on the last day of the range to 00:10 the next morning is counted in neither period.
Which days and hours of the week your chargers are busiest.
A session is counted at the hour it **ended**, so one running from 09:00 to 13:00 lands in the 12–14 block rather than being spread across four.
The percentage of the period your network was either charging or idle.
Idle covers the OCPP statuses that mean a vehicle is connected without drawing power: `Preparing`, `Finishing`, `SuspendedEV`, and `SuspendedEVSE`.
Your locations ranked by sessions, energy consumed, or occupancy rate.
The percentage of the period in which your EVSEs were not in a faulted state, measured as aggregate EVSE-hours across whatever your filters include.
That definition has three consequences:
* An EVSE reporting `Unavailable` counts as up. Only `Faulted` counts against uptime.
* A charge box being offline does not enter the calculation.
* An EVSE that took no sessions at all counts as up for the whole period.
If you report uptime to a site host or in a tender, state which definition you are using. This one measures fault-free EVSE time, which is one of several things the word is used to mean.
## Dependencies & limitations
* **Transaction value is not revenue.** The figure is net of VAT and before the commercial agreements behind your invoice.
* **Uptime measures fault-free EVSE time.** `Unavailable` EVSEs and offline charge boxes do not reduce it.
* **The CO₂ figure is a gross estimate.** It is calculated from consumption and does not subtract the emissions of the electricity used.
* **Active users counts authorisation charge keys, not people.** One driver with two cards counts twice, a shared fleet card counts once, and payment terminal and unauthenticated sessions each collapse to a single user.
## Related
To take these figures into a spreadsheet or a reporting tool of your own, use an export rather than the page itself.
Getting CDR data and the Dashboard view out of Connect for your own analysis.
The records every period metric on this page is built from.
Connector-by-connector detail behind the live charger status card.
What the customer and location filters narrow the page to.
# Exports
Source: https://docs.spirii.com/capabilities/reporting-analytics/exports
Take your charging data into Excel, your finance system, or your own reporting.
Exports give you Spirii Connect's data as a CSV file, filtered however you need it. Most of the value sits in the charge detail record export, which carries each completed session along with the location, driver, tariff, and pricing context behind it.
## Overview
Two things in Connect can be exported, and they behave differently. For anything you need on a schedule, the API is the better route — see [When to use the API instead](#when-to-use-the-api-instead).
One row per completed session, with 50-plus columns of context. Generated in the background and collected from the Exports page.
The figures behind the Dashboard's period metrics, one row per connector per day. Downloads straight away.
## Charge detail record exports
A charge detail record export is the same population you see on the Charge detail records page, written to a CSV. Because a CDR carries the location, driver, tariff, and pricing context around each session, one file can serve reconciliation, employee reimbursement, utilisation analysis, and sustainability reporting without you joining it to anything else.
### Filtering before you export
The export inherits the filters currently set on the page, so narrow the view first. The filters differ depending on which side of the business you are looking at.
* Location
* Customer
* Authentication type
* Network
* Started between
* Ended between
* Priority
* Authentication type
* EVSE operator network
* Authentication customer
* Started between
* Ended between
* Priority
Authentication type covers how the session was authorised, such as an app, a charge key, or a payment terminal. Network covers how the session reached Spirii, whether directly, through Hubject, or over OCPI.
### Exporting from a single location, charge key, or app user
The Charge detail records tab also appears on individual location, charge key, and app user pages. Exporting from there gives you only that entity's sessions, which is the quickest route to a single driver's reimbursement claim or one site's monthly figures.
### Choosing the field delimiter
Before the export runs you choose the field delimiter. This is a locale setting: pick the one your spreadsheet expects and the file opens in columns.
| Delimiter | Use it where |
| - | - |
| Semicolon | Continental Europe, South America, and anywhere a comma is the decimal separator |
| Comma | The UK, United States, Mexico, and anywhere a period is the decimal separator |
### Following an export
CDR exports are generated in the background. Small ones finish in seconds; a quarter or a year of data across a large network takes a few minutes.
Find them under **your name** at the bottom of the menu, then **Exports**. The table lists each export with its generation status, creation date, the operator or company it covers, the filename, the file type, the file size, and a download button once it is ready. The page refreshes every ten seconds, so the percentage counter advances while the file builds.
## What a CDR export contains
Each row is one completed session. The columns fall into eight groups.
The record's own ID, plus the EVSE and charge box it ran on. These are what you join against if you are combining the export with data from elsewhere.
The location's ID, name, address, and type, whether it is public, and the customer that owns it — including that customer's billing reference and CRM identifier. Also the operator network and operator name behind the site.
This is the group that lets you split a report by site, by customer, or by the entity you invoice.
The authentication type, and then the identifiers behind it: the app user, the charge key's UID, its label and comment, and the billing customer the charge key belongs to with its own reference and CRM identifier.
Also the authentication provider and provider network, which say whose driver it was, and a flag for whether Spirii treated the session as roaming.
When the session started, ended, and was created, along with charging time and idle time in seconds.
Charging time and idle time are separate columns, so you can tell a slow session from a car left plugged in after it finished.
Meter start and end values, total consumed, and maximum power reached. Where the charge box reports it, the vehicle's state of charge at the start and end of the session.
Total price including and excluding VAT, the VAT rate and amount, and the currency. Alongside them, the payment method and payment status.
The VAT split is already calculated, so a finance team does not have to derive it.
The name of the tariff applied, whether it was dynamic, and the roaming tariff identifier where one applied. Where a voucher was used, its group and ID.
The component fees that produced the total: energy fees with the consumption and price behind each, time fees with the minutes and price behind each, and any flat fees.
This is where you show a customer how a price was arrived at, rather than only what it came to.
## Reading a charge detail record export
Four things are worth knowing before you build anything on top of the file.
* **Blank and zero mean different things.** A blank cell means the value does not apply to that row. A `0` is a measured value and belongs in a sum.
* **Fee columns can hold several values in one cell.** Where a tariff has multiple components, the values are separated by a pipe inside the cell, like `2,544 | 4,895 | 4,624`. Split on the pipe before you total anything.
* **Timestamps use one timezone.** They are written in central European time, with the timezone included. They are not converted to each location's local time, so if you are analysing time of day across markets, shift them first.
* **The roaming flag reflects Spirii's view, not yours.** It marks whether a session arrived through an external roaming provider or from inside Spirii's own ecosystem, which means a driver belonging to a different Spirii operator is not flagged as roaming. To separate your own drivers from visitors, compare the authentication provider against your own operator name rather than reading that column.
## Dashboard exports
The Dashboard export writes out the figures behind the page's period metrics, at a finer grain than the page shows them. One row covers one connector on one day, using the filters and time range currently set.
| Group | What it holds |
| - | - |
| Scope | Date, customer, location, EVSE ID, charge box ID, connector ID |
| Volume | Sessions, distinct users, energy consumed |
| Time | Charging time, idle time, time occupied, and average duration, all in seconds |
| Commercial | Revenue excluding VAT, and the currency |
| Availability | Uptime as a percentage |
Because the grain is a connector-day, the file answers questions the page cannot: which connector underperformed last Tuesday, how utilisation varies across one site, how a single customer's estate trended over a month. Group the rows however your question needs.
A connector that took no sessions shows 100% uptime, which follows from how the metric is defined.
Two things the file does not carry. The comparison against the previous period is calculated in the view, so recompute it from the dates if you need it. And the daily grain cannot reproduce the heatmap's hour-of-day pattern — that needs session start and end times from a charge detail record export.
Dates are written in ISO form here, where a charge detail record export uses day-first timestamps, so watch the format if you combine the two files.
The delimiter is not selectable here: Dashboard exports are always semicolon-delimited. These files are small, so they download in your browser straight away.
## When to use the API instead
A manual export suits a question you are answering once, or a report someone assembles by hand each month.
For anything recurring, the [charge detail records API](/api-reference/charge-records-v2/get-a-list-of-cdrs) is the better route. It returns the same session data as a feed you can schedule, which is how partners build their own dashboards, reconcile automatically, and drive billing without anyone opening Connect.
## Dependencies & limitations
* **Large exports take time.** There is no cap on what you can request, but a year of data across a large network takes minutes rather than seconds.
* **Only CDR exports queue.** The Exports page lists charge detail record exports. Dashboard exports download immediately and do not appear there.
* **The export mirrors your filters exactly.** Anything excluded by a filter is absent from the file, so set the filters before you export.
* **Installer and Depot Manager roles cannot export.** Every other role can.
## Related
If you are exporting for the first time, set your filters before you start. The file is built from whatever the page is showing.
What a charge detail record is, and when it becomes final.
The aggregated view these figures are drawn from.
The same session data as a feed, for recurring reporting.
Which roles in your organisation can export.
# Network coverage
Source: https://docs.spirii.com/capabilities/roaming/network-coverage
Plan routes, check a region, and judge whether a site fits — before you commit to it.
The **Charge map** shows you every charger your drivers can reach in one view: your own network, public sites, and the networks you reach over roaming.
## Overview
Anyone running fleet or mobility charging faces one operational question first: where can my drivers actually charge? The Charge map answers it in Spirii Connect, across every network you can reach rather than only the sites you operate.
It's the view you plan from, not the in-the-moment map drivers use in Spirii Go.
## How it works
You'll find the Charge map in Connect under **Network**. It opens on the locations you can reach, and from there you:
* switch between your own locations and the full network you can access
* pan and zoom to a region, or search by name, city, or address
* click a location pin to open its details and see the chargers and connectors on site
For example, a fleet operator planning a long-haul corridor opens the map, searches along the route, filters to sites with the right connector that can take a heavy vehicle, and checks each candidate's chargers before assigning it to drivers.
## Filters
Filters turn a crowded map into a shortlist that fits the need. Start broad, then add one or two until the results are manageable.
| Filter | Narrows to | Use it when |
| - | - | - |
| Operator | Locations run by a specific operator or network | You only want sites on one network you have an agreement with |
| Vehicle type | Sites suited to a vehicle class: truck with trailer, rigid truck, bus, or semi-tractor | You're planning for heavy vehicles rather than cars |
| Connector type | Sites with a compatible plug or standard, such as CCS | The vehicle needs a particular connector |
| Facilities | Sites with the amenities a driver needs, such as rest areas | Drivers need breaks or facilities on a long route |
## When to use it
Check where drivers can charge along the corridor before you assign it, rather than finding the gap once a driver is already on the road.
Filter to sites with a compatible connector that can take the vehicle class, so a driver isn't sent somewhere their truck can't physically use.
Confirm the coverage is there before onboarding drivers who will expect it.
## Set up
The Charge map is part of Connect for eMSP and fleet admin accounts. There's nothing to install. What you see on it depends on which networks you can reach — [Roaming connection](/capabilities/roaming/roaming-connection) covers how that access is established.
## Dependencies & limitations
* **Visibility and planning only.** It shows where charging is and whether a site fits a need; it doesn't navigate, plan routes, or start a charge.
* **Coverage reflects the networks you can reach.** Sites on networks you don't have access to don't appear on the map.
* **Vehicle type comes from the operator.** Each operator publishes the vehicle types their sites suit, so a site that would take your vehicle can be missing from a filtered result if its operator hasn't published that detail.
* **It's an admin view in Connect**, separate from the driver-facing map in Spirii Go.
## Related
How the networks beyond your own become reachable, and how they're priced and settled.
The driver-facing map, where the same coverage reaches the people charging.
What each pin on the map represents.
The chargers and connectors you inspect at a site.
# Roaming connection
Source: https://docs.spirii.com/capabilities/roaming/roaming-connection
How Spirii connects your chargers and your drivers to the networks you don't operate.
Roaming puts your chargers in front of drivers from other networks, and gets your own drivers charging on networks you don't operate.
## Overview
Spirii supports roaming on both sides of your business, and what it does for you depends on the role you're in:
Publish and price your chargers for roaming. Spirii exposes them to drivers on other networks, and you see the resulting sessions and revenue — without building a driver base of your own.
Connect your drivers to other networks' chargers. Your charge keys and branded app reach roaming chargers across the ecosystem, so your drivers always have somewhere to charge.
## How it works
Spirii connects to the roaming ecosystem on your behalf, in two ways:
* **Roaming hubs** — marketplaces like Hubject, Gireve, and e-clearing.net that aggregate many CPOs and eMSPs. Spirii's network is connected to the major hubs, so once you enable roaming, your chargers reach the drivers on them and your drivers reach their chargers.
* **Direct integrations** — one-to-one connections to specific networks, built over the OCPI protocol and maintained by Spirii. You reach these without negotiating an agreement of your own.
```mermaid theme={null}
flowchart LR
A("Your chargers, published as a CPO") --> S("Spirii platform")
B("Your charge keys and app, as an eMSP") --> S
S --> H("Roaming hubs")
S --> D("Direct OCPI connections")
H --> N("Other networks: their drivers and their chargers")
D --> N
```
Spirii manages the connection, the data exchange, and [settlement](/capabilities/billing-payouts/roaming-settlement) for both.
## Pricing
As a CPO, you set a **roaming tariff** per location in Spirii Connect: a flat rate per kWh, and the price you're paid. You enter it gross, so it's comparable with your standard tariff, but eMSPs are billed the net amount, which is what you receive. Account for the platform fees that apply to roaming sessions so your margin holds. [Roaming pricing](/capabilities/pricing/pricing-options-and-logic#roaming-pricing) covers how the tariff is chosen and when a change takes effect.
What a driver ultimately pays can differ. When a driver from another network charges on your chargers, their own eMSP decides their final price.
As an eMSP, your drivers pay the host CPO's price for a roaming charge, passed through to your branded app.
## When to use it
Publishing your chargers across roaming brings in drivers who would never install your app, lifting usage on every location you expose.
Roaming brings third-party drivers from day one, before you've built up loyal local drivers of your own.
Roaming gives your drivers access to charge points across other networks, so there's always somewhere to charge.
## Set up
What you do depends on your side.
### As a CPO
Publish and price your chargers. Each location you want on roaming must be:
* Set to **public**, with **roaming enabled** and a **roaming tariff** set
* Given a **latitude and longitude**
* Using **connector IDs** in the eMI3 format — the EVSE ID plus the connector number, asterisk-separated, such as `DE*SPI*E00012345*1`. Invalid IDs keep a charger off roaming.
That format derives from your CPO operator ID, or prefix, such as `DE*SPI`. Spirii helps set the prefix up once you've registered it with your local national registry and the roaming hubs have approved it.
[Set up a public charging hub](/guides/public-charging-hub) covers this alongside the rest of a public site.
### As an eMSP
Connect your charge keys and app. Each charge key your drivers use must be:
* **Active** and **roaming-enabled**
* Labelled following the recommended format `DK.SPI.C{customerPrefix}` to avoid interoperability issues — Spirii converts the label to the formats hubs and OCPI require behind the scenes
Drivers reach roaming chargers through your branded app or Spirii Go, where they appear alongside your own network's. [Fleet quickstart](/guides/fleet-quickstart) covers issuing the keys and getting drivers on the road.
## Dependencies & limitations
* **Roaming depends on more parties.** A roaming session involves the CPO, the eMSP, and often a hub, so more can interrupt a charge than on a session within your own network.
* **Data formatting is strict.** Location, EVSE, and charge key data must follow the required formats (see Set up); incorrect data is the most common reason a charger doesn't appear or a session fails.
* **The eMSP controls the final price and its own data.** You can't set what a driver pays on your chargers over roaming, and a change you make — price or status — appears in the eMSP's app only as fast as they refresh it.
## Related
How the money moves in both directions once sessions are exchanged.
See and filter the chargers your drivers can reach over roaming.
Enable roaming and set the roaming tariff per location.
How an eMSP's drivers authenticate across networks.
Where the connector IDs roaming requires come from.
The records exchanged over roaming and used to settle each charge.
# Overview
Source: https://docs.spirii.com/capabilities/smart-charging/overview
Programmatic control of chargers and Dynamic Load Management circuits, and the async events Spirii emits.
The Energy Management Async API lets a registered **Actor** — an external entity granted control over a set of chargeboxes and/or circuits — programmatically manage Dynamic Load Management, and receive the resulting events and telemetry.
## Integration model
Actors interact with this API in two directions, over two different transports:
Control commands go to the `controlRequest` channel — a single HTTP endpoint handling all command types. The call is fire-and-forget: it only confirms the request was authenticated and queued, not that it succeeded.
Results and telemetry are published by Spirii, per actor, to a set of AWS SNS topics created during actor registration: `controlResponse`, `connectorStatusUpdate`, `masterData`, `powerMeasurements`.
During registration/subscription, each Actor subscribes an endpoint to each topic it wants to receive — any valid SNS subscription protocol can be used, e.g. an AWS SQS queue, a HTTPS callback, AWS Lambda, etc. The subscription can be updated after the fact.
Concrete server addresses and queue ARNs are provisioned during actor onboarding and communicated to each Actor separately; they are not part of this reference.
Only the actor-control channels are covered here.
## Full specification
The complete AsyncAPI 3.0 document backing this reference, in YAML — every channel, message schema, and example shown here in one file.
# Changelog
Source: https://docs.spirii.com/changelog/overview
Connect to the latest updates, improvements, and fixes to Spirii’s platform
## Manage reimbursement rates in Spirii Connect
### What's improved
Home charging reimbursement rates used to sit on the Company Car agreement, or be managed through the Spirii API. You can now manage them in Connect, on the location each rate applies to.
* **Rates tab on each location:** every reimbursement rate for the location, with its start date, end date, currency, and rate per kWh. The active rate also shows on the location overview.
* **Add and edit rates:** set a start date, an optional end date, the currency, and the rate per kWh.
* **Supporting documents:** attach evidence such as an electricity bill when you add or edit a rate, then download or remove it later. Use it to validate a rate or to support a tax audit.
* **Applied rate on the CDR:** the CDR details show which reimbursement rate was applied to the session.
* **Checked on save:** a rate's period is checked against the location's other rates when you save it. If the period conflicts, the save is rejected and an error explains why.
### Why it matters
You can now set the rate, see which one applies to an employee's home, and keep the evidence behind it, all in one place.
### How it works
When a location has a reimbursement rate, that rate is used instead of the rate on the Company Car agreement. Locations without a rate of their own keep using the agreement rate, so you can move them over at your own pace.
Rates created through the Spirii API appear in Connect, and rates created in Connect are available through the API. Integrations that already manage rates need no changes.
### What a rate supports
* Each rate is a flat price per kWh for a period. Variable contracts such as spot-price tariffs, day and night pricing, and regulated rates aren't supported.
* A rate must be above 0 and no higher than 10 per kWh, with at most four decimals. The maximum is the same in every currency.
* Rates can't be deleted in Connect. Delete a rate with the [Spirii API](/api-reference/reimbursement-rates/delete-a-reimbursement-rate-and-its-attached-documents), unless it's locked because an expense report has used it.
* Drivers can't add or manage rates in Spirii Go or a branded app.
### Who is this for?
* **Segment:** B2B Fleet, and CPOs serving fleet customers
* **Users:** Fleet managers in Spirii Connect; operators onboarding fleet customers onto reimbursement; integrators managing rates through the Spirii API
* **Markets:** All markets
### Next steps
See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) for the full cycle, or the [Reimbursement rates API](/api-reference/reimbursement-rates/get-reimbursement-rates-for-one-or-more-locations).
## Reimburse every session at a home charger
### What's improved
Until now, a home charging session was only reimbursed if the employee started it with their charge key. If they forgot to tap, they paid for that session themselves. A new location setting reimburses every session at the location to its owner, whether or not a charge key was used.
* **New location setting:** *Reimburse all sessions to the location owner*, in the Reimbursement section when you create or edit a location in Connect.
* **Off by default:** existing locations keep reimbursing charge key sessions only.
* **Visible on the overview:** the Pricing and billing card shows whether the location reimburses charge key sessions only or all sessions.
* **Self-serve:** you set it when you configure the location, with no request to Spirii.
### Why it matters
On a home charger with one driver, requiring a charge key adds nothing, because the location already knows who it belongs to. What it does produce is missed reimbursements. Every forgotten tap is a session the employee has to chase, and across a fleet those turn into payroll queries and manual corrections. Attributing sessions by location removes the problem at the source.
### Single-driver locations
The setting applies to the whole location. Every session recorded there is reimbursed to the location owner, including sessions charged by someone else, and there's no per-driver or per-connector control. Where more than one driver uses the charger, keep reimbursement on charge key sessions. At any location without the setting, a charge key is still required to be reimbursed.
### Who is this for?
* **Segment:** B2B Fleet, and CPOs serving fleet customers
* **Users:** Operators and fleet managers who create and edit locations in Spirii Connect; company car drivers charging at home
* **Markets:** All markets
### Next steps
See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) for how sessions become expense reports.
## Lower reservations on private, non-roaming locations
### What's improved
When a driver starts a session, we reserve an estimated amount on their card before any energy is delivered. On locations that are not public and do not have roaming enabled, that reservation is now roughly a third of what it was.
* The reservation is still calculated from the location's tariff, using a lower multiplier for these locations
* Locations that are public, or that have roaming enabled, are unchanged
* The minimum reservation amount has been removed, so locations on low tariffs see the full reduction rather than being rounded back up
### Why it matters
Workplace charging is the clearest case. An employee charging at their employer's site now has an amount reserved that reflects a session at that location, rather than one sized to cover charging anywhere on the network. Less of their own money is held while they charge, and the reservation they see is closer to the price they pay.
### How it works
A location qualifies automatically when both of these are set on its location edit page in Connect:
* Public availability is off
* Roaming is not enabled
Nothing needs to be configured or requested. Locations that already meet both conditions are using the lower reservation now.
### Reservation amounts
Reservations are calculated per session from the location's tariff, and the calculation is tuned over time to keep card authorisation rates high. The reserved amount is an estimate, not a fixed figure, and the driver's statement shows the reservation separately from the final charge.
### Who is this for?
* **Segment:** B2B Fleet, and workplace or employee charging in particular
* **Users:** Drivers paying by card at private locations; CPOs and site owners managing non-public locations in Spirii Connect
* **Markets:** All markets
### Next steps
See [Pre-authorisation and capture](/capabilities/payments/pre-auth-capture) for how reservations and captures work across app and terminal sessions.
## Chargers moving to a new OCPP endpoint
### What's improved
We're retiring our legacy OCPP endpoint. Its replacement has been live in production for nine months and now becomes the connection point for every charge box. All new development happens on this endpoint going forward.
This is a change to the OCPP connection between your hardware and Spirii, not to the Spirii API.
### Timeline
Chargers move over the coming weeks and months, brand by brand, starting with the models we've already proven on the new endpoint. Migration work happens in maintenance windows on Tuesdays and Thursdays, 09:00 to 12:00 CET, though some waves run outside these windows.
We don't give individual sites a migration date. If your site needs coordination on our side, we'll contact you directly.
**If your chargers connect through a proxy or middleware platform, you need to repoint it yourself, by 31 October 2026.** See below.
### What happens when a charger moves
* Its OCPP URL changes to `wss://ocpp.spirii.com` and it restarts.
* It's offline for the restart, usually under a minute. If a charger is still offline 30 minutes after its migration, we investigate.
* We never migrate a charger with an active or unfinished session, since the restart would cancel it.
* Nothing else changes: tariffs, location, and historical data stay exactly as they are.
If you want to check whether a specific charger has already moved, look at its OCPP configuration in Connect. If the charger is managed through a manufacturer portal, such as Zaptec Cloud or Easee Cloud, check there instead.
### What you need to do
For most operators: nothing. The migration happens on our side, and your chargers reconnect automatically.
```mermaid theme={null}
flowchart TD
A{"Do your chargers connect to Spirii through a proxy or middleware platform?"} -->|No| B("Nothing to do. Your chargers migrate automatically.")
A -->|Yes| C("Repoint the proxy to wss://ocpp.spirii.com before 31 October 2026")
C --> D("Confirm the proxy connects over TLS 1.2")
```
If your chargers reach us through a proxy or middleware platform, you need to repoint that connection to `wss://ocpp.spirii.com` yourself, before 31 October 2026. We can't do this for you, and we won't migrate those chargers until you have. `wss://ocpp.spirii.com` requires TLS 1.2, so make sure your proxy connects securely.
For any new charge point you onboard from now on, use `wss://ocpp.spirii.com` as the OCPP endpoint.
### Do you connect through a proxy?
Some charge points don't connect to Spirii directly. Instead, the charger connects to a third-party platform, and that platform connects to Spirii on the charger's behalf. From our side, we see the platform, not the charger behind it. Repointing the OCPP connection without the platform also being repointed would cut those chargers off.
```mermaid theme={null}
flowchart LR
subgraph Direct["Most chargers"]
C1("Charger") --> S1("Spirii")
end
subgraph Proxied["Behind a proxy"]
C2("Charger") --> M("Proxy or middleware platform")
M --> S2("Spirii")
end
```
In the direct case, the charger's own OCPP connection moves to `wss://ocpp.spirii.com` automatically. In the proxied case, only the platform's connection needs to move, and only you can move it.
Known proxies and middleware in use on our platform include Panion, K2, FLEXeCHARGE, GAO Charge, Easee Cloud, and Zaptec Cloud.
Many operators don't know they're behind one, because the installer or hardware supplier set the connection up at commissioning. If you're not sure, ask whoever installed or commissioned your chargers:
* Does our charger connect to Spirii directly, or through your platform?
* If through your platform, can you repoint the OCPP connection to `wss://ocpp.spirii.com`, and confirm it supports TLS 1.2?
### Hardware that can't move yet
Some older charge box models can't support TLS 1.2 on any available firmware. These stay on the current connection for now. If this applies to you, we'll contact you directly.
### Who is this for?
* **Segment:** All segments operating charge points through Connect
* **Users:** CPOs and charge point owners using Spirii Connect
* **Markets:** All markets
### Next steps
Questions about this migration go to [support@spirii.com](mailto:support@spirii.com).
If you operate behind a proxy, let us know once you've repointed it so we can confirm your chargers arrived at the new endpoint.
## Introducing App User V2 endpoints
### What's new
This update introduces app user management capabilities through new API endpoints. App users represent the end customers of operators utilizing a branded app.
### New endpoints
* [`GET /v2/app-users`](/api-reference/app-users/get-a-list-of-app-users) — retrieves a paginated list of app users
* [`POST /v2/app-users`](/api-reference/app-users/create-app-user) — create a new app user
* [`GET /v2/app-users/{id}`](/api-reference/app-users/get-app-user-by-id) — get a single app user by id
* [`PUT /v2/app-users/{id}`](/api-reference/app-users/update-app-user) — update an existing app user
**Access restriction:** These endpoints are exclusively available to operators with a branded app deployment.
## Vouchers and voucher groups
### What's new
You can now manage vouchers and voucher groups through the public API. A voucher, identified by a unique code, belongs to a voucher group and can be linked to charge keys and app users. When a driver starts a session, the platform applies a voucher automatically if their charge key — or the app user linked to it — holds one, provided the voucher's group covers that location.
### New endpoints
**Vouchers**
* [`GET /v2/vouchers`](/api-reference/vouchers/get-a-list-of-vouchers)
* [`POST /v2/vouchers`](/api-reference/vouchers/create-a-new-voucher)
* [`GET /v2/vouchers/{id}`](/api-reference/vouchers/get-a-voucher-by-id)
* [`PATCH /v2/vouchers/{id}`](/api-reference/vouchers/update-an-existing-voucher)
* [`DELETE /v2/vouchers/{id}`](/api-reference/vouchers/delete-a-voucher-by-id)
* [`GET /v2/vouchers/{id}/tokens`](/api-reference/vouchers/get-tokens-associated-with-a-voucher-by-voucher-id)
* [`POST /v2/vouchers/{id}/tokens/{tokenId}`](/api-reference/vouchers/associate-a-token-to-a-voucher)
* [`DELETE /v2/vouchers/{id}/tokens/{tokenId}`](/api-reference/vouchers/disassociate-a-token-from-a-voucher)
**Voucher groups**
* [`GET /v2/voucher-groups`](/api-reference/vouchergroups/get-a-list-of-voucher-groups)
* [`POST /v2/voucher-groups`](/api-reference/vouchergroups/create-a-new-voucher-group)
* [`GET /v2/voucher-groups/{id}`](/api-reference/vouchergroups/get-a-voucher-group-by-id)
* [`PATCH /v2/voucher-groups/{id}`](/api-reference/vouchergroups/update-an-existing-voucher-group)
* [`DELETE /v2/voucher-groups/{id}`](/api-reference/vouchergroups/delete-a-voucher-group-by-id)
* [`GET /v2/voucher-groups/{id}/vouchers`](/api-reference/vouchergroups/get-a-paginated-list-of-vouchers-belonging-to-a-voucher-group)
* [`GET /v2/voucher-groups/{id}/locations`](/api-reference/vouchergroups/get-voucher-groups-locations-by-id)
* [`POST /v2/voucher-groups/{id}/locations/{locationId}`](/api-reference/vouchergroups/associate-location-to-voucher-group)
* [`DELETE /v2/voucher-groups/{id}/locations/{locationId}`](/api-reference/vouchergroups/disassociate-locations-from-voucher-group)
### Next steps
Explore the [API Reference](/api-reference/vouchers/get-a-list-of-vouchers) for detailed specifications on these new endpoints, or see the [Voucher access](/capabilities/access/voucher-access) capability for how vouchers grant access and pricing.
## Price Optimised Charging
### What's new
We just launched **Price Optimised Charging**. You've always been able to manually schedule charging sessions overnight to avoid peak prices — now the system finds the cheapest intervals for you, automatically.
You decide when your vehicles need to be ready, and the system schedules charging during the cheapest electricity periods, ensuring every vehicle is ready on time without any manual intervention.
* No more manually scheduling sessions around tariff hours
* The system monitors electricity prices and charges when it's cheapest
* Vehicles are always ready on time — the schedule is built around your needs
* If something changes, you can override any session instantly in Connect
### Why it matters
Electricity costs directly impact profitability for your fleet, and every cent saved per kWh goes straight to the bottom line. Price Optimised Charging shifts consumption to cheaper windows automatically, reducing operational cost without requiring manual work.
### How it works
* Set a charging window (start time → end time) and specify how many hours of charge are needed. Spirii selects the cheapest intervals within that window automatically.
* Powered by live spot price data from Nordpool/ENTSO-E, with fallback to day-ahead forecasted prices when final prices are unavailable.
* The system prevents schedules from overlapping with opening hours, at both the frontend and backend level.
### Hardware compatibility
Your chargers must support the Smart Charging feature set as defined in OCPP 1.6. If your charger doesn't appear in the table when you open the schedule modal, it is unfortunately not supported.
### Who is this for?
* **Segment:** B2B Fleet
* **Users:** Fleet managers and site managers operating via Spirii Connect
* **Markets:** Austria, Belgium, Germany, Denmark, Estonia, Spain, Finland, France, Great Britain, Lithuania, Latvia, Netherlands, Norway, Poland, Portugal, Sweden
## Introducing home charging reimbursement rates
### What's new
Home Charging Reimbursement now supports configurable, scheduled custom rates. View and manage reimbursement rates associated with customer locations.
### New endpoints
* [`GET /reimbursement/rates/v1`](/api-reference/reimbursement-rates/get-reimbursement-rates-for-one-or-more-locations)
* [`POST /reimbursement/rates/v1`](/api-reference/reimbursement-rates/create-a-new-reimbursement-rate)
* [`PATCH /reimbursement/rates/v1/{id}`](/api-reference/reimbursement-rates/update-an-existing-reimbursement-rate)
### Next steps
Explore the [API Reference](/api-reference/reimbursement-rates/get-reimbursement-rates-for-one-or-more-locations) for detailed specifications on these new endpoints.
## Expense reports for charging at home
### What's new
For expense reports that you need to reimburse to employees, you now have increased capabilities for getting this data into your payroll or expense management tools.
**Key capabilities:**
* As a Fleet Manager or Operator in Connect, you can now receive expense reports:
* [Via the public API](/api-reference/reimbursement-expenses/get-expense-report)
* As a PDF, emailed to you or downloaded via Connect
* As a CSV file downloaded via Connect
### Why it matters
This gives you multiple ways to access expense report data, so you can adapt to your internal operations and share data with your systems and colleagues.
### Who is this for?
Fleet Managers who manage expenses for charging at home.
## Introducing smart payment reservations
### What's improved
We've introduced a **smart reservation** feature that sets the reservation amount dynamically based on the expected final price in Spirii Go and branded apps.
* This guarantees a reserved amount high enough to cover the cost of the charging session, but not unnecessarily high.
* If the charging ends up more expensive, we attempt to increment the reservation (where possible) to the new amount.
We've also improved **reservation reuse** when charging fails to start.
* If you have to start over at the charge point, we don't create a new reservation on your card — one is enough.
For edge cases where payments fail despite everyone's best efforts (the issuing bank is momentarily down, your charge key expires during the session, and similar):
* We retry payment for the charging session a few times over the following days.
### Why it matters
Together, these updates create a better experience for drivers and reduce the risk of missing payment for charging.
## Soft delete for charge keys in Connect UI
### What's new
Charge keys can now be soft deleted via the Connect UI.
**Key functionality:**
* Soft delete action in the charge keys sidebar
* Soft deleting a charge key also unlinks the payment method from the charge key
* Confirmation modal
### Why it matters
Connect users no longer have to open a support ticket for the simple action of deleting a charge key.
### Who is this for?
Anyone, in all markets.
## Introducing home charging reimbursements
### What's new
A CPO can use the public APIs to build their own experience for managing home charging expenses and reimbursement. The Spirii platform continues to handle charger configuration, charge key and location management, reimbursement validation, expense report aggregation, approval workflows, PPS integration, and document generation.
### New endpoints
* [`GET /reimbursement/v1/expense-reports`](/api-reference/reimbursement-expenses/list-expense-reports)
* [`GET /reimbursement/v1/expense-reports/{id}`](/api-reference/reimbursement-expenses/get-expense-report)
* [`GET /reimbursement/v1/expense-reports/{id}/document`](/api-reference/reimbursement-expenses/download-expense-report)
* [`POST /reimbursement/v1/expense-reports/{id}/approve`](/api-reference/reimbursement-expenses/approve-expense-report)
* [`GET /reimbursement/v1/expenses/{id}`](/api-reference/reimbursement-expenses/get-expense)
* [`GET /reimbursement/v1/expenses/{id}/document`](/api-reference/reimbursement-expenses/download-expense)
* [`GET /reimbursement/v1/expenses/{id}/charge-detail-records/unlinked`](/api-reference/reimbursement-expenses/list-unlinked-cdrs)
* [`POST /reimbursement/v1/expenses/{id}/charge-detail-records/add`](/api-reference/reimbursement-expenses/add-cdrs-to-expense)
* [`POST /reimbursement/v1/expenses/{id}/charge-detail-records/remove`](/api-reference/reimbursement-expenses/remove-cdrs-from-expense)
### Next steps
Review the [API Reference](/api-reference/reimbursement-expenses/list-expense-reports) for comprehensive endpoint specifications.
## AFIR DATEX II-ready API endpoints
### What's new
We're releasing our DATEX II v3 endpoints, designed to help meet the requirements of the Alternative Fuels Infrastructure Regulation (AFIR). This update allows seamless, automated sharing of infrastructure data with National Access Points across the EU ahead of the April 2026 deadline.
**Key functionality:**
Our platform now provides public, unauthenticated endpoints that automatically convert and serve your existing Location v2 API data in the mandatory DATEX II format.
* Static data endpoints: full snapshots of sites, stations, and connectors
* Dynamic data endpoints: real-time availability and up-to-date pricing information
* Smart sync (delta pulls): support for `If-Modified-Since` headers, letting National Access Points pull only changed data, reducing bandwidth and improving sync speed
### Why it matters
Staying compliant with EU regulations shouldn't be a technical burden. As of April 2026, all public CPOs in the EU are legally required to share data in the DATEX II v3 format. This update removes the regulatory blocker, keeping your charging network visible, compliant, and accessible to major industry players without requiring your team to build or maintain a custom reporting engine.
## AFIR — DATEX II energy infrastructure data
### What's new
We're introducing AFIR-compliant DATEX II v3 endpoints, enabling public access to energy infrastructure data for your charging network. These endpoints support the Alternative Fuels Infrastructure Regulation (AFIR) reporting requirements by exposing standardised static and dynamic charging infrastructure data.
Both endpoints are publicly accessible — no authentication required.
### New endpoints
* [`GET /v2/afir/energy-infrastructure-tables`](/api-reference/afir/get-datex-ii-v3-afir-energy-infrastructure-tables)
* [`GET /v2/afir/energy-infrastructure-statuses`](/api-reference/afir/get-datex-ii-v3-afir-energy-infrastructure-statuses)
### Key changes and improvements
| Endpoint | Feature | Description |
| - | - | - |
| `GET /v2/afir/energy-infrastructure-tables` | Static infrastructure data | Retrieve a DATEX II v3 payload with site, station, refill point, connector, operating hours, and tariff metadata. |
| `GET /v2/afir/energy-infrastructure-statuses` | Dynamic infrastructure statuses | Retrieve a DATEX II v3 payload with real-time site, station, and refill point statuses, including dynamic tariff updates. |
Both endpoints support:
* Gzip compression for optimised payload delivery
* Conditional caching via `If-Modified-Since` / `304 Not Modified`
* Customer filtering via the optional `customerIds` query parameter
### Next steps
* Explore the [API Reference](/api-reference/afir/get-datex-ii-v3-afir-energy-infrastructure-tables) for detailed specifications.
* Read more in the [AFIR compliance guide](/developers/afir-compliance).
## Upgraded EVSE power settings and opening hours
### What's improved
Recent highlights in Spirii Connect:
* **EVSE power settings:** added configuration options for maximum output voltage and maximum output current (amps) to enable precise electrical parameter control per EVSE. Also available in the [Spirii API](/api-reference/evses-v2/updates-a-connector-on-an-evse).
* **Opening hours UI:** improved usability for opening hours configuration. Public availability settings have moved out of the opening hours modal and are now controlled from the location edit page.
### Why it matters
* Flexible connector power settings allow for more accurate EVSE power data and boost roaming exposure of EVSEs.
* The opening hours UI now more clearly distinguishes between 24/7 availability and specific day-based schedules.
## Reduced failed payments with advanced reservation amount logic
### What's improved
We've implemented more advanced payment reservation amount logic.
* Instead of a fixed pre-authorisation amount per country or operator, we now base the reservation amount on the tariff at each location.
* This produces a reservation amount much closer to the actual price for most users at the location.
### Why it matters
Early data shows a 95% reduction in failed payments.
## Enhanced EVSE power settings
### What's new
We've enhanced EVSE configuration with new power parameters for more precise control over EVSE electrical specifications.
### Key changes and improvements
Updated endpoint:
* [`PATCH /evses/{id}`](/api-reference/evses-v2/updates-a-connector-on-an-evse) — now supports additional power configuration fields
New fields:
* `maxVoltage` — maximum voltage output (V), per the OCPI specification
* `maxAmperage` — maximum current output (A), per the OCPI specification
Existing fields:
* `maxElectricPower` — maximum power output (kW)
* `standard` — connector type, per the OCPI specification
These enhancements let you configure precise electrical parameters for each EVSE independently, aligning with physical hardware specifications without affecting other EVSEs on the same charge box.
### Next steps
For detailed field specifications and examples, visit the [API Reference](/api-reference/evses-v2/updates-a-connector-on-an-evse). If you have questions about implementing these parameters, contact our support team.
## Dual user roles for more flexibility
### What's new
We've added flexibility to user management in Spirii Connect:
**Key capabilities:**
* Each user can now have multiple roles (for example, Fleet Manager and Supporter).
* The Fleet Manager role has been updated to handle reimbursements.
### Why it matters
Organisations are flexible, so we updated the roles to support more of your use cases.
## Introducing expense management for home reimbursements
### What's new
Spirii now supports home reimbursements in all markets with a new expense management model.
**Key capabilities:**
* Let the Spirii platform gather all the charging data and prepare the expense management files.
* Use the files in your own payroll system to pay employees.
* Optionally, add or remove CDRs to include in the expense report.
### Why it matters
* This home reimbursement model lets fleet operators offer home charging to their employees.
* It's a light setup with easy onboarding.
### Who is this for?
Fleet Operators.
## Upgraded exports
### What's improved
* **Dashboard export:** added an EVSE ID column for better charge point identification.
* **CDR exports:** now include the billing customer CRM ID for easier customer identification.
### Why it matters
We continuously upgrade the data available to you to improve your reporting and operations.
## Upgraded installer role
### What's improved
We're expanding the installer role to better support installation teams while protecting business-critical data. The updated installer role now includes:
* Location lookup — find and access installation sites quickly
* Charge box and connector management — view, add, and configure hardware during installation
* Charge box actions — perform essential actions without needing full admin access
* Session access for testing — verify installations are working correctly in real time
### Why it matters
* Previously, the installer only had access to order lookup, which restricted their ability to work efficiently.
* Business information stays secure: installers cannot view tariffs or pricing details.
## Charge box management endpoints
### What's new
We've introduced comprehensive charge box management capabilities, enabling you to programmatically manage your physical charging hardware through the API.
### New endpoints
* [`GET /chargeboxes`](/api-reference/chargeboxes-v2/fetches-a-list-of-charge-boxes)
* [`GET /chargeboxes/{id}`](/api-reference/chargeboxes-v2/fetches-a-single-charge-box)
* [`GET /chargeboxes/models`](/api-reference/chargeboxes-v2/fetches-a-list-of-supported-charge-box-models)
* [`POST /chargeboxes`](/api-reference/chargeboxes-v2/creates-a-new-charge-box)
* [`DELETE /chargeboxes/{id}`](/api-reference/chargeboxes-v2/deletes-a-charge-box-this-operation-cannot-be-undone)
### Key changes and improvements
| Endpoints | Feature | Description |
| - | - | - |
| `GET /chargeboxes`, `GET /chargeboxes/{id}` | Charge box information | Retrieve a list of all charge boxes in your network with filtering and pagination support, or fetch detailed information about a specific charge box. |
| `GET /chargeboxes/models` | Charge box model information | Retrieve a list of supported and validated charge box models. |
| `POST /chargeboxes` | Charge box configuration | Create and onboard new charge boxes to your network. |
| `DELETE /chargeboxes/{id}` | Charge box deletion | Remove charge boxes from your network (soft delete). |
### Next steps
Explore the [API Reference](/api-reference/chargeboxes-v2/fetches-a-list-of-charge-boxes) for detailed specifications.
## Enhanced remote charger control, EVSE management, and charge key management
### What's new
This update introduces comprehensive remote charger control and enhanced EVSE management, alongside charge key and charge key group management for programmatic control.
#### Remote charge box commands
* Soft reset: graceful restart that preserves data and configurations
* Hard reset: full hardware reboot for unresponsive charge boxes
#### EVSE management and commands
* Transaction control
* Remote start: initiate charging sessions remotely
* Remote stop: end active sessions remotely
* Unlock connector: remotely release connector locks on AC chargers
* Retrieve EVSE information: list all EVSEs or fetch specific details
* Update EVSE settings: modify properties such as maximum power output
* Change connector availability: update OCPP availability status
#### Charge key management — full CRUD operations
Charge keys authenticate users to initiate charging sessions. Three types are supported: RFIDs, virtual charge keys, and vehicle charge keys. Full CRUD operations enable management as well as enable and disable functionality.
#### Charge key group management — full CRUD operations
Charge key groups act as access-management mechanisms that restrict charge key authorisation to specified locations. Full CRUD operations manage location and charge key associations.
### New endpoints
Remote charge box management:
* [`POST /chargeboxes/{id}/reset`](/api-reference/chargeboxes-v2/performs-a-hard-or-soft-reset-on-a-charge-box)
* [`POST /chargeboxes/{id}/reboot`](/api-reference/chargeboxes-v2/reboots-a-charge-box-alias-for-soft-reset)
EVSE management:
* [`POST /evses/{uid}/connectors/{id}/remote-start-transaction`](/api-reference/evses-v2/requests-an-evse-to-start-a-transaction)
* [`POST /evses/{uid}/connectors/{id}/remote-stop-transaction`](/api-reference/evses-v2/requests-an-evse-to-stop-a-transaction)
* [`POST /evses/{uid}/connectors/{id}/unlock`](/api-reference/evses-v2/requests-an-evse-to-unlock-a-connector)
* [`GET /evses`](/api-reference/evses-v2/fetches-a-list-of-evses)
* [`GET /evses/{id}`](/api-reference/evses-v2/fetches-a-single-evse)
* [`PATCH /evses/{id}/connectors/{connectorId}`](/api-reference/evses-v2/updates-a-connector-on-an-evse)
* [`POST /evses/{id}/connectors/{connectorId}/change-availability`](/api-reference/evses-v2/updates-the-availability-status-of-a-connector)
Charge key management:
* [`GET /tokens`](/api-reference/tokens/get-a-list-of-tokens)
* [`GET /tokens/{id}`](/api-reference/tokens/get-a-token-by-id)
* [`POST /tokens`](/api-reference/tokens/create-a-new-token)
* [`PATCH /tokens/{id}`](/api-reference/tokens/update-a-token)
* [`DELETE /tokens/{id}`](/api-reference/tokens/delete-a-token)
* [`POST /tokens/{id}/enable`](/api-reference/tokens/enable-a-token)
* [`POST /tokens/{id}/disable`](/api-reference/tokens/disable-a-token)
Charge key group management:
* [`GET /token-groups`](/api-reference/token-groups/get-a-list-of-token-groups)
* [`GET /token-groups/{id}`](/api-reference/token-groups/get-a-token-group-by-id)
* [`POST /token-groups`](/api-reference/token-groups/create-a-new-token-group)
* [`PATCH /token-groups/{id}`](/api-reference/token-groups/update-a-token-group)
* [`DELETE /token-groups/{id}`](/api-reference/token-groups/delete-a-token-group)
* [`POST /token-groups/{id}/enable`](/api-reference/token-groups/enable-a-token-group)
* [`POST /token-groups/{id}/disable`](/api-reference/token-groups/disable-a-token-group)
* [`GET /token-groups/{id}/locations`](/api-reference/token-groups/get-a-list-of-locations-associated-to-a-token-group-by-id)
* [`POST /token-groups/{id}/locations/{locationId}`](/api-reference/token-groups/associate-a-location-to-a-token-group)
* [`DELETE /token-groups/{id}/locations/{locationId}`](/api-reference/token-groups/disassociate-a-location-from-a-token-group)
* [`GET /token-groups/{id}/tokens`](/api-reference/token-groups/get-a-list-of-tokens-associated-to-a-token-group-by-id)
* [`POST /token-groups/{id}/tokens/{tokenId}`](/api-reference/token-groups/associate-a-token-to-a-token-group)
* [`DELETE /token-groups/{id}/tokens/{tokenId}`](/api-reference/token-groups/disassociate-a-token-from-a-token-group)
### Use cases
For NOC and support teams:
* Troubleshoot issues remotely without site visits
* Assist drivers with authorisation and stuck sessions
* Unlock connectors when cables are stuck
For CPOs:
* Build custom monitoring and alerting solutions
* Perform maintenance without taking charge boxes offline
* Manage fleet operations efficiently
* Bulk-create and manage charge keys
* Manage location access via charge key groups
### Next steps
* Read more about [remote commands](/capabilities/operation-monitoring/remote-commands).
* Explore the [API Reference](/api-reference/evses-v2/fetches-a-list-of-evses) for implementation details.
## Introducing temporary EVSE status and full Locations CRUD
### What's new
This release introduces two major upgrades to the Spirii API.
#### Temporary EVSE status
Temporary EVSE status lets charge point operators modify the charger status shared with e-Mobility Service Providers. The feature updates the displayed charger status in eMSP apps without altering the actual charger status.
Use cases include:
* Maintenance mode
* Commissioning
* Parking sensors
* Reservation systems
New endpoints:
* [`POST /v2/temporary-evse-statuses`](/api-reference/temporary-evse-statuses-v2/create-a-new-temporary-evse-status)
* [`GET /v2/temporary-evse-statuses`](/api-reference/temporary-evse-statuses-v2/get-all-temporary-evse-statuses)
* [`GET /v2/temporary-evse-statuses/{id}`](/api-reference/temporary-evse-statuses-v2/get-a-temporary-evse-status-by-id)
* [`PATCH /v2/temporary-evse-statuses/{id}`](/api-reference/temporary-evse-statuses-v2/update-a-temporary-evse-status)
* [`DELETE /v2/temporary-evse-statuses/{id}`](/api-reference/temporary-evse-statuses-v2/remove-a-temporary-evse-status)
#### Locations V2 — full CRUD operations
Locations V2 now includes create, update, and delete operations alongside the existing GET endpoints.
New endpoints:
* [`POST /v2/locations`](/api-reference/locations-v2/creates-a-new-location)
* [`PATCH /v2/locations/{id}`](/api-reference/locations-v2/updates-an-existing-location)
* [`DELETE /v2/locations/{id}`](/api-reference/locations-v2/deletes-an-existing-location-this-operation-cannot-be-undone)
### What's deprecated
The Locations V1 update endpoint is now deprecated: `PUT /locations`. Partners should migrate to V2 as soon as possible.
### Migration and next steps
* All V1 partners should transition to V2 immediately.
* The V1 endpoint remains operational but will be fully sunset at a later date.
* Breaking changes exist; migrating to V2 is recommended.
* Read more about [temporary EVSE status](/capabilities/operation-monitoring/temporary-evse-status).
## Introducing Locations V2 and Tariffs V2 for AFIR compliance
### What's new
We've introduced Locations V2 and Tariffs V2 under the Spirii API.
Operators of public chargers can use these GET endpoints to comply with the EU's Alternative Fuels Infrastructure Regulation (AFIR) article 20, which took effect on 14 April 2025.
The added endpoints also provide extended data fields for location management and public-charging pricing compared with the legacy Locations endpoint. Both endpoints are structured and formatted in compliance with OCPI version 2.3.0.
New endpoints:
* [`GET /v2/locations`](/api-reference/locations-v2/fetches-a-list-of-locations)
* [`GET /v2/locations/{id}`](/api-reference/locations-v2/fetches-a-single-existing-location)
* [`GET /v2/tariffs/{id}`](/api-reference/tariffs-v2/fetches-a-single-existing-tariff)
### What's deprecated
The Locations V1 endpoints are now deprecated under the Spirii Legacy API:
* `GET /locations`
* `GET /locations/{id}`
Partners using these endpoints should migrate to V2 as soon as possible.
### Key changes and improvements
| Change | Endpoints | Description |
| - | - | - |
| Locations | `GET /v2/locations`, `GET /v2/locations/{id}` | Format upgraded to the OCPI 2.3.0 structure; added data for facilities, opening hours, directions, contact information, and energy mix. |
| Tariffs | `GET /v2/tariffs/{id}` | Format upgraded to the OCPI 2.3.0 structure; added data for tariff type, price components, and price restrictions. |
### Migration and next steps
* All partners using V1 should transition to V2 as soon as possible.
* The V1 endpoint remains operational for now but will be fully sunset at a later date (to be announced).
* If you use V1, update your integrations accordingly and reach out if you need support.
Some properties are no longer available in V2 and the structure has changed in a breaking manner. If you are using V1, we strongly recommend migrating now to take advantage of the new capabilities and ensure long-term compatibility. See the API documentation for full details.
## Bug fixes
### What's fixed
We fixed various bugs across the Transaction V2 and Voucher endpoints.
| Change | Endpoints | Description |
| - | - | - |
| Bug fix | `GET /v2/transactions`, `GET /v2/transactions/{id}` | Fixed an issue with the `startedAt` filter not being applied. |
| Bug fix | `GET /vouchers`, `GET /vouchers/{id}` | Fixed an issue retrieving voucher groups where the `companyId` was `null`. |
| Bug fix | `GET /vouchers`, `GET /vouchers/{id}` | Fixed an issue where the response included deleted voucher groups (a populated `deletedAt` timestamp). These are now filtered out. |
## Introducing Transaction V2
### What's new
We've introduced Transaction V2 under the Spirii API. This new version increases readability, introduces new transaction properties, and improves the overall response structure and filtering capabilities.
New endpoints:
* [`GET /v2/transactions`](/api-reference/transactions-v2/get-a-list-of-transactions)
* [`GET /v2/transactions/{id}`](/api-reference/transactions-v2/get-a-transaction-by-id)
### What's deprecated
The Transaction V1 endpoints are now deprecated under the Spirii Legacy API:
* `GET /v1/transactions`
* `GET /v1/transactions/{id}`
Partners using these endpoints should migrate to V2 as soon as possible.
### Key changes and improvements
| Change | Transaction V1 | Transaction V2 |
| - | - | - |
| Data structure | — | Response structure changes: an `auth` object is added; the `location` object returns `type`, `countryCode`, and `isEligibleForRefund` properties; the `price` object is expanded for VAT and tariff information; the `user` object is replaced by `appUserId`; a `chargingDetails` object is added with charging status, state-of-charge meter values, and CO₂ emissions data; a `company` object is added; a `paymentStatus` object is added. |
| Data structure | `meterValues` object contains all meter values | `meterValues` is deprecated, replaced by `meterStart` and `meterStop` properties in the `chargingDetails` object. |
| Pagination | Offset-based | Cursor-based for better scalability. |
| Filtering | Limited filtering options | Enhanced filtering: `ongoing`, `chargeBoxId`, `evseId`, `locationType`, `transactionType`, `voucherId`. |
### Migration and next steps
* All partners using V1 should transition to V2 as soon as possible.
* The V1 endpoint remains operational for now but will be fully sunset at a later date (to be announced).
* If you use V1, update your integrations accordingly and reach out if you need support.
Some properties are no longer available in V2 and the structure has changed in a breaking manner. If you are using V1, we strongly recommend migrating now to take advantage of the new capabilities and ensure long-term compatibility. See the API documentation for full details.
# App users
Source: https://docs.spirii.com/components/access/app-users
Manage the drivers signed up to your branded app, and what they can charge with.
An app user is a driver who has an account in Spirii Go or a branded app, and the record in Spirii Connect that holds their details, payment methods, and charging history.
## Overview
An app user is created when a driver signs up in an [app](/capabilities/driver-experience/spirii-go-and-branded-apps), or by an [onboarding flow](/capabilities/automation/onboarding-flows) — the web ordering journey where a driver orders a charger, a subscription, or a charge key. The record itself is light. A name, contact details, and a creation date are all it holds directly, and its value comes from what attaches to it: the charge keys the driver charges with, the cards they pay with, the home charger they control, and their session history.
In Connect, App users is where you find a driver, confirm what they can charge with, and see what they have used.
## Context
An app user belongs to the partner whose app they signed up in. The driver sets that boundary at sign-up when they accept the app owner's terms and conditions, and Connect enforces it: only the partner who owns the app can see the record. Where an onboarding flow has associated the user with a customer, that customer can manage them too.
You can delete an app user from Connect. When a driver deletes their own account in the app, an anonymised identifier is all that remains on their charge detail records (CDRs), so session and billing history stays intact without the person attached to it.
An anonymised identifier is also what appears when a driver from another partner's app charges on your locations. Their account sits behind that partner's boundary, so the session is attributed without the driver being exposed to you.
There is no app user over [roaming](/capabilities/roaming/roaming-connection). A driver reaching another network appears there as a [charge key](/components/access/charge-keys), and nothing about the account behind it crosses the boundary.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| ID | Unique identifier for the app user | `48213` |
| First name | The driver's given name | `Lena` |
| Last name | The driver's family name | `Weber` |
| Email | The address the account is registered to | `lena.weber@example.com` |
| Phone number | Optional contact number | `+49 151 2345 6789` |
| Newsletter | Whether the driver opted in to marketing email at sign-up | `true` |
| Created | When the account was created | `14 Feb 2026` |
| App | The app the driver signed up in, which controls who can see the record | `Acme Charging` |
| Customer | Optional. The customer that can also manage the user, set by an onboarding flow | `Lindenhof Housing` |
A driver who signs up in the app on their own has no customer set. Spirii support can assign one on request, but in practice the onboarding flow that created the account makes the association.
## Relationships
The first two fields above scope who can see and manage an app user. Everything else about the driver hangs off the record.
```mermaid theme={null}
flowchart TD
A("App\nSpirii Go or a branded app") --> AU("App user")
AU --> T("Charge keys")
AU --> CC("Credit cards")
AU --> V("Vouchers")
AU --> RL("Residential location\nhome charger")
AU --> SE("Sessions and CDRs")
```
### Charge keys
A driver can hold several [charge keys](/components/access/charge-keys), and each charge key belongs to at most one app user. To move a charge key to a different driver, unbind it from the current one first. You can make the link from either side in Connect, from the charge key or from the app user, and a driver can add a charge key themselves in the app when it arrives.
Charge keys do not need an app user at all. A fleet operator running a pool of RFID charge keys shared across vehicles leaves them unassigned.
### Credit cards
A driver's saved cards appear in Connect as the card brand, the last four digits, and the expiry date. The card details themselves stay with the payment provider and are never stored in the Spirii platform, so this is the full extent of what Connect shows.
### Vouchers
A [voucher](/components/access/vouchers) appears on an app user's account once the driver enters its code in the app. The voucher group behind it sets which locations that driver can use, and on what price conditions.
### Residential locations
An app user attached to a residential location — a driver's home, shown in Connect under Locations — can control the charger there: charging schedules, authentication, and the charger's other settings. More than one app user can be attached to the same residential location, which is how a household shares a charger, though most have a single user.
An onboarding flow creates the location, the customer, and the app user together and binds them, so a driver who ordered a home charger arrives with the attachment already in place.
### An app user is not every driver
Plenty of charging happens without one. All of these produce sessions and CDRs on your network:
| Who charged | What you see |
| - | - |
| One of your app users | The app user, with their details |
| A driver from another partner's app | An anonymised identifier, and no app user record |
| A driver who has deleted their account | An anonymised identifier |
| A driver charging anonymously in Spirii Go | No user |
| A shared fleet charge key | The charge key, with no app user behind it |
On a public network, most sessions will have no app user attached, and the CDR is still complete for billing and reporting.
## Used in
Each app user's charging is recorded as CDRs. See [Sessions and CDRs](/components/charging/sessions-and-cdrs) for how those records are structured and billed.
The charging history attached to each driver.
What a driver authenticates and charges with.
The party that can manage a user alongside the app owner.
Access and pricing granted to a driver's account.
# Charge keys
Source: https://docs.spirii.com/components/access/charge-keys
Who's allowed to charge, and who gets billed for it.
A charge key is a unique identifier that authenticates a driver to start a charging session.
## Overview
Charge keys are the central object for [authenticating and authorising](/capabilities/access/charge-key-authentication) charging sessions: they define *who* is charging on a network and *whether* they're allowed to. A charge key is an umbrella over several identification technologies: RFID cards, virtual identifiers in an app, and vehicle identification by MAC address or VIN (known as Autocharge).
Over [roaming](/capabilities/roaming/roaming-connection), the charge key is what lets a driver authenticate across networks, and what links each [CDR](/components/charging/sessions-and-cdrs) to the party that should be billed.
In the API, charge keys are called **tokens** and charge key groups are called **token groups** — for example `GET /v2/tokens`. The object is the same; only the name differs.
## Context
A charge key is primarily an eMSP object — it's how a provider gives drivers access — but it works on both sides of a charge.
### eMSP context
For an eMSP, charge keys are how you identify your drivers and give them access to charge — on Spirii's network, and over roaming across other networks too. You register and manage the charge keys, and the billing customer on each one determines who's invoiced for its usage. For roaming, charge keys are exchanged with connected CPOs over hubs and direct integrations, so they must follow the roaming standard's (OCPI) rules; we recommend eMI3 formatting like `DK.SPI.C{customerPrefix}` to avoid interoperability issues.
### CPO context
For a CPO, charge keys are a channel to sell access to your infrastructure. When a driver presents a valid charge key at a public, online location, the platform authorises the session and handles the rest.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| Type | The charge key type (see Types below) | `RFID` |
| UID | The charge key's unique identifier. For RFID cards, this is the MiFare UID. | `A7E942F1C8D036B5A429` |
| Label | A free-text label for recognising the charge key in the platform, often the text printed on the physical card | `DE.SPI.00012345` |
| Billing customer | The customer in the platform billed for the charge key's usage | `Acme Inc.` |
| Billing reference | A free-text reference shown on invoices | `Fleet Vehicle #123` |
| Active | Whether the charge key can start sessions on Spirii's network | `true` |
| Roaming | Whether the charge key can start sessions over roaming | `true` |
| Expires at | When the charge key's activation expires | `23:59:59, 31 Dec 2025` |
| App user | The linked app user in a Spirii app, if any | `Spirii Go User 12345` |
## Types and status
### Types
| Type | Description |
| - | - |
| RFID | A physical card or fob with an embedded MiFare chip. |
| Virtual | A digital identifier in a Spirii app, used as a payment method for monthly invoicing. |
| Vehicle (Autocharge) | The vehicle's MAC address or VIN, read by the charger when the cable is plugged in. |
Autocharge only works on chargers managed by Spirii's platform, not over roaming. A driver relying on Autocharge won't be recognised on other operators' chargers.
### Status
A charge key's ability to start a session comes from two independent settings: Active (on Spirii's CPO network) and Roaming (over roaming), so a charge key can have either, both, or neither. An expiry overrides both: once past its `Expires at` date, a charge key can't authorise sessions regardless of those settings.
Deleting a charge key is the third way it stops authorising. Deletion is a *soft* delete: the key is set inactive and can no longer start sessions, but its record stays in the platform rather than being removed. Deleting a charge key also unlinks the payment method from it. You can delete a charge key from its sidebar in Spirii Connect, which asks you to confirm first.
Deletion is permanent for that UID: once a charge key is deleted, you can't register a new one with the same UID. For a physical RFID card, that means the card can't be re-registered afterwards. To stop a charge key charging temporarily, set it inactive instead of deleting it.
## Used in
Exchange charge keys with other networks over OCPI.
Register and manage charge keys programmatically.
Organise charge keys into groups for shared access and billing.
# Vouchers
Source: https://docs.spirii.com/components/access/vouchers
How an operator opens selected locations to a specific group of drivers, at a price they control.
A voucher is a code that gives a chosen group of drivers access to selected locations, at a price you set.
## Overview
A voucher does two things at once:
Grants a chosen group of drivers access to a set of locations.
Sets what those drivers pay at the locations it covers.
An operator uses it to open their chargers to a known audience (fleet drivers, employees, residents, VIPs) on terms that don't touch the public price.
A voucher overrides the location's standard tariff. While it's active, the holder pays the voucher price, not the public price, at every location attached to it.
A voucher can also reveal locations that aren't on the public network at all, so it doubles as a way to keep a set of chargers private to the group that holds the code. Treat the access as the primary job and the price as a setting on top: the cleanest setup links the voucher to a tariff for pricing, so the voucher controls *who* and *where*, and the tariff controls *how much*.
## Context
Vouchers are an operator's tool, and they work only within Spirii's own mobility surfaces. A CPO creates and manages them in Spirii Connect for their own locations, and a driver redeems a voucher in Spirii Go or a branded app. A voucher can also be linked to a Spirii charge key, so the charge key itself carries the access. Vouchers aren't shared with external eMSPs and don't travel over roaming; they grant access on the Spirii network only.
## Key attributes
A voucher has two levels: the **voucher group** that sets the terms, and the **vouchers** — the codes issued under it.
### Voucher group
| Attribute | Description | Example |
| - | - | - |
| Customer | The customer the group belongs to | `Acme Inc.` |
| Name | A clear name for the group, plus an optional internal note | `Acme partner fleet` |
| Price | What voucher users pay at the attached locations. Set it with a linked tariff (recommended); a fixed or dynamic price can also be set on the group | `Partner DC (0,45 €/kWh)` |
| Locations | The locations the voucher grants access to, and where its price applies | `Munich DC Hub`, `Hamburg Depot` |
### Voucher
| Attribute | Description | Example |
| - | - | - |
| Code | The code a driver enters in the app to activate the voucher | `ACME-2026-0042` |
| Max users | Optional cap on how many drivers can use the code | `25` |
| Expires at | Optional date the code stops working | `31 Dec 2026` |
## Relationships
### Vouchers, app users, and charge keys
A redeemed voucher doesn't stand on its own; it connects to the things that carry its benefit, and the link between the three is worth getting straight:
* A voucher links directly to the **app users** who redeem its code. Entering the code attaches that app user to the voucher (up to its max-users limit), which is what applies the access and price to their account.
* A voucher can also be linked to a **charge key**, granting that charge key the same access and pricing benefits, so a driver charging with the charge key gets the voucher's locations and price without entering the code in an app.
The same voucher therefore reaches a driver two ways: through the app user who redeemed the code, or through a charge key it's linked to.
## Used in
Create voucher groups, issue codes, and open locations to a user group.
The price a voucher should link to.
The sites a voucher grants access to.
A voucher can be linked to a charge key to carry its access.
# Charge boxes
Source: https://docs.spirii.com/components/charging/charge-boxes
Where you manage a charger's firmware, connectivity, and remote commands.
A charge box is the physical unit installed at a site: the cabinet that houses one or more EVSEs.
## Overview
A charge box is the hardware asset in the [charger hierarchy](#relationships): it sits beneath a location and above the EVSEs it contains. When an operator provisions a charger onto a location, the charge box is the object that represents that physical unit in the platform.
It holds the settings that belong to the unit as a whole ([firmware version](/capabilities/operation-monitoring/firmware-management), configuration keys, and connectivity) and it records the [unit's logs](/capabilities/operation-monitoring/charger-history-and-logs), such as OCPP message logs and connectivity history. [Remote commands](/capabilities/operation-monitoring/remote-commands) that act on the whole unit, like a reboot, are issued at this level.
To check which OCPP endpoint a box is currently connected to, open its OCPP configuration in Spirii Connect. For a unit managed through its manufacturer’s own cloud portal, check the endpoint there instead.
## Context
A charge box is an operator-side object: you manage it in Connect and the Spirii API, and it has no direct equivalent over roaming. The OCPI standard has no charge box layer — it works at the EVSE level and groups EVSEs directly under the location. So a box's data isn't lost over roaming, it's folded into its EVSEs: a box that goes offline surfaces to drivers as an inoperative EVSE, while operator-only details such as firmware stay on the Spirii side.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| ID | Unique identifier for the charge box in the Spirii platform | `12345` |
| Charge box ID (CBID) | The operator-facing identifier; the platform uses it to generate the IDs of the EVSEs on the box | `DE*SPI*E00012345` |
| Vendor | The hardware manufacturer | `Alpitronic GmbH` |
| Model | The specific hardware model | `HYC_400` |
| Firmware | The firmware version currently installed | `hyc_2.4.0` |
| Online | Whether the box is currently connected to the platform | `true` |
| Last connection event | Timestamp of the most recent ping from the box | `14:00:44, 27 Jan 2025` |
The `ID` is the platform's internal reference; the `CBID` is what an operator works with, and it seeds the IDs of the EVSEs the box contains.
## States
A charge box reports its connection status to the platform:
| State | Meaning |
| - | - |
| Online | The box is connected to the platform and ready to charge |
| Offline | The platform hasn't received a ping from the box recently |
Charging states, such as charging or faulted, are tracked at the EVSE level rather than on the box.
## Relationships
A charge box sits in the middle of the charger hierarchy: below the location it belongs to, above the [EVSEs](/components/charging/evses-and-connectors) it serves. It inherits site-level settings from its location, such as geolocation, access, and pricing, and passes its connection status down to its EVSEs.
```mermaid theme={null}
flowchart TD
L("Location") --> CB1("Charge box\nAC")
L --> CB2("Charge box\nDC")
CB1 --> E1("EVSE")
CB2 --> E2("EVSE")
CB2 --> E3("EVSE")
E1 --> C1("Connector\nType 2")
E2 --> C2("Connector\nCCS")
E2 --> C3("Connector\nCHAdeMO")
E3 --> C4("Connector\nCCS")
```
## Used in
The charging units a charge box contains, and where its data surfaces over roaming.
Retrieve and manage charge boxes programmatically.
# EVSEs
Source: https://docs.spirii.com/components/charging/evses-and-connectors
Where charging happens, and the object roaming and billing are built on.
An EVSE is the part of a charge box that supplies electricity to one EV at a time.
## Overview
EVSE stands for Electric Vehicle Supply Equipment: the component of a charge box that supplies a connected vehicle's battery. It's both the hardware and the software that manage the charging process — the part of the charger that communicates with the vehicle.
A connector is the physical plug a driver attaches to the vehicle. An EVSE usually has a single connector, though it can have more. Spirii models both the EVSE and the connector as levels in the [charger hierarchy](#relationships).
## Context
An EVSE matters on both sides of a charge — it's where charging physically happens, and the object roaming is built on.
### CPO context
For a CPO, the EVSE and its connectors are the charging hardware you model in Spirii Connect: their standard, power, and status. The EVSE ID is derived from the [charge box](/components/charging/charge-boxes) it belongs to. The attributes below describe that model.
### eMSP context
For an eMSP, the EVSE is the primary object reached over [roaming](/capabilities/roaming/roaming-connection). Across OCPI, the EVSE is what signals operability to other networks, and what each CDR attaches to for settlement. Complete, correctly formatted connector data is what makes a charger usable over roaming, and the charging status maps to OCPI as shown under States.
## Key attributes
### EVSE
| Attribute | Description | Example |
| - | - | - |
| EVSE ID | The unique, eMI3-compliant identifier | `DE*SPI*E00012345` |
| Status | The current charging status (see [States](#states)) | `charging` |
The EVSE ID is derived automatically from the [charge box's](/components/charging/charge-boxes) CBID — you don't assign it yourself.
### Connector
| Attribute | Description | Example |
| - | - | - |
| Connector ID | The connector number, appended to the EVSE ID | `1` (`DE*SPI*E00012345*1`) |
| Standard | The plug type | `CCS 2` |
| Power type | AC or DC | `DC` |
| Max power | The theoretical maximum power, in kW | `400` |
| Max voltage | The theoretical maximum voltage, in V | `1000` |
| Max amperage | The current in A, auto-calculated from power and voltage | `400` |
| Error | Error codes and information reported by the charger | `UnderVoltage`, `NO_VOLTAGE_L2_L3` |
| Availability | Whether the connector is temporarily disabled, via the `SetAvailability` command | `Unavailable` |
## States
An EVSE's charging status follows OCPP 1.6 and maps to OCPI 2.1.1 for roaming:
| Status (OCPP) | OCPI mapping | Meaning |
| - | - | - |
| `Available` | `Available` | No vehicle is plugged in; the EVSE is ready to start a session |
| `Preparing` | `Charging` | A session is being prepared, e.g. after a valid charge key is presented |
| `Charging` | `Charging` | The vehicle is actively charging |
| `Finishing` | `Charging` | The flow of electricity has stopped and the transaction is concluding |
| `SuspendedEV` | `Blocked` | The vehicle stopped the transaction but is still plugged in |
| `SuspendedEVSE` | `Blocked` | The charger stopped the transaction but the vehicle is still plugged in |
| `Faulted` | `OutOfOrder` | The charger registered an error |
| `Unavailable` | `Inoperative` | The EVSE is temporarily out of service |
Spirii doesn't use OCPP's `Reserved` status.
## Relationships
An EVSE and its connectors sit at the bottom of the charger hierarchy. The EVSE inherits its charge box's connectivity; box-level commands such as `reboot` are issued on the charge box and affect the EVSEs it contains.
```mermaid theme={null}
flowchart TD
L("Location") --> CB1("Charge box\nAC")
L --> CB2("Charge box\nDC")
CB1 --> E1("EVSE")
CB2 --> E2("EVSE")
CB2 --> E3("EVSE")
E1 --> C1("Connector\nType 2")
E2 --> C2("Connector\nCCS")
E2 --> C3("Connector\nCHAdeMO")
E3 --> C4("Connector\nCCS")
```
## Used in
Publish your EVSEs to other networks over OCPI.
The unit an EVSE belongs to, and where its ID comes from.
Retrieve EVSE and connector data programmatically.
# Locations
Source: https://docs.spirii.com/components/charging/locations
What a location is, what it contains, and how it connects to the rest of the platform.
A location is the container for the chargers at a single physical site: the entity that every charge box, tariff, session, and access rule is organised under.
## Overview
A location is the top of the [charger hierarchy](#the-charger-hierarchy): before a charge box can come online, it has to belong to one. It holds the site's identity (name, address, geolocation, and type) and anchors the pricing, access, operational, and financial settings that apply to everything installed there.
Because so much hangs off it, how you set up a location shapes how every charger on the site behaves.
## Context
What a location is depends on which side of the platform you work from.
### CPO context
For a CPO, a location is a site you operate. You [create it](/capabilities/connection/location-configuration), set its [pricing](/capabilities/pricing/pricing-options-and-logic) and [access](/capabilities/access/location-access), and [bring chargers online](/capabilities/connection/charger-activation) under it. The attributes, types, and states below describe a location as Spirii Connect models it for the operator.
### eMSP context
For an eMSP, a location isn't something you operate — it's a node you reach for your drivers, over roaming. You don't work with the Connect model below. Instead you receive a read-only representation published by the operator, which follows the roaming standard's (OCPI) conventions rather than Connect's: the location types, the charger structure, and even the meaning of "published" differ. [Roaming](/capabilities/roaming/roaming-connection) covers how that exchange works.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| ID | Unique identifier for the location | `12345` |
| Name | Free-text name; shown to drivers in the app | `Munich DC Hub` |
| Customer | The customer that owns the location in the platform | `Acme Inc.` |
| Address | Street, postcode, city, and country | `Bayerstraße 10a, 80335 München, Germany` |
| Coordinates | Latitude and longitude, used to place the map pin in apps | `48.0827, 11.5550` |
| Public | Whether the location is visible and usable in Spirii apps and with charge keys | `true` |
| Roaming enabled | Whether the location is published to roaming networks | `true` |
| Tariff | The tariff setting the price and conditions for public charging via Spirii apps and charge keys | `Public DC (0,50 €/kWh)` |
| Roaming tariff | The tariff for charging via roaming networks | `SPI-230 (0,50 €/kWh)` |
## Types and states
The types and states below are Spirii's CPO model in Connect, as introduced under Context; an eMSP reaching the location over roaming sees OCPI's values instead.
### Location types
| Type | Description | Typical use |
| - | - | - |
| Residential | A home charging location | Private B2C charging, company-car home charging |
| Public road | A publicly available site | Highway hubs, on-street and urban parking |
| Parking lot | A public site at a parking area | Depots, retail, workplace charging |
| Parking lot (indoor) | A parking building | Multi-storey car parks |
| Parking lot (underground) | An underground parking garage | Basement car parks |
| Hotel | A charging location at a hotel | Hotels |
Residential locations aren't publicly priced, but they're not tariff-free: a free residential tariff is assigned automatically in the background.
### Location states
A location's state is derived from the chargers installed on it:
| State | Meaning |
| - | - |
| Online | One or more chargers are online and ready to charge |
| Pending | The location is commissioning, awaiting installation and activation of its first charger |
| Offline | One or more of the location's chargers are disconnected |
| Faulted | One or more of the location's chargers are faulted |
## Relationships
A location sits at the top of the charger hierarchy and anchors four kinds of settings across the site: pricing, access, operations, and financial.
### The charger hierarchy
Chargers on a location are structured in four levels:
* **Location:** the full site
* **Charge box:** an individual physical unit
* **EVSE:** the part of a charge box that can serve one EV at a time; each has its own ID and a status, such as Charging or Available
* **Connector:** the socket or cable an EV plugs into, with its plug type (e.g. CCS), power type (e.g. DC), and maximum power (e.g. 150 kW)
```mermaid theme={null}
flowchart TD
L("Location") --> CB1("Charge box\nAC")
L --> CB2("Charge box\nDC")
CB1 --> E1("EVSE")
CB2 --> E2("EVSE")
CB2 --> E3("EVSE")
E1 --> C1("Connector\nType 2")
E2 --> C2("Connector\nCCS")
E2 --> C3("Connector\nCHAdeMO")
E3 --> C4("Connector\nCCS")
```
## Used in
Publish the location to roaming networks and price it for roaming.
The chargers that come online under a location.
# Sessions and CDRs
Source: https://docs.spirii.com/components/charging/sessions-and-cdrs
What billing, reporting, and roaming settlement are built on.
A session tracks a single charging event from start to finish. A charge detail record (CDR) is the immutable, billable record of a completed session.
## Overview
A session captures everything that happens during a charge — not just the flow of electricity, but the events around it. It usually begins when a driver plugs in and authenticates (though it can start earlier, for example when a charger is reserved) and ends when the driver unplugs.
When the session concludes, the platform generates a CDR: the immutable record of the completed charge, carrying all the data needed for billing, operations, and reporting.
## Context
What a session and CDR represent depends on which side of the charge you're on. The CDR is the industry-standard data foundation for invoicing between CPOs and eMSPs over roaming — but it's the source data an invoice is built from, not an invoice itself.
### CPO context
Sessions and CDRs represent every charging event on your infrastructure, organised by the EVSE IDs in your network where the charging happened. The goal is to invoice each eMSP that accessed your network during the period.
### eMSP context
Sessions and CDRs represent every charging event your drivers authorised, organised by the charge key UIDs they used. The goal is to pay each CPO invoice for the charging your drivers did.
## Key attributes
### Session
Session data is dynamic: while a charge is in progress, it updates as new meter values arrive from the charger.
| Attribute | Description | Example |
| - | - | - |
| Transaction ID | The session's unique identifier | `12345678` |
| EVSE ID | The EVSE where the charge takes place | `DE*SPI*E00012345` |
| Charging details | Live data about the electricity flow: consumed kWh, status, and vehicle state of charge (SoC) | `34 kWh`, `charging`, `78%` |
| Duration | Charging time and idle time | `5432 seconds`, `340 seconds` |
| Started at | When the session started | `10:46:57, 23 Jun 2026` |
| Authentication | Who initiated the session (UID, type, and billing reference) | `12345678910`, `RFID`, `Acme Inc.` |
| Roaming details | The roaming connection involved: role, network, and operator | `EMP`, `Hubject`, `EnBW` |
| Price | Amount, currency, and VAT rate | `20.71`, `EUR`, `19%` |
| Payment method | How the driver paid | `Payment terminal` |
| Payment status | The status of the payment | `Succeeded` |
### CDR
A CDR carries every session field in its final state, plus the financial data used for billing.
| Attribute | Description | Example |
| - | - | - |
| Ended at | When the session ended | `12:23:09, 23 Jun 2026` |
| Price breakdown | The final price split into per-interval components, pipe-separated, for dynamic or conditional fees | `2.57` \| `2.64` \| `2.99` \| `…` |
| Card | The credit card used (brand and last four digits) | `VISA`, `1234` |
| Payment metadata | Extra data for payment-terminal sessions: masked PAN, merchant ID, terminal ID | `123456******1234`, `Spirii ApS`, `12345` |
| Roaming details (extended) | Additional roaming financials, such as whether the session is billable | `true` |
For sessions on chargers in Spirii's own network, the CDR also attaches contextual platform data for CPO reporting:
| Attribute | Description | Example |
| - | - | - |
| CPO default price | The standard price the driver would have paid without a voucher | `28.89`, `EUR` |
| Location | Details of the EVSE's location: type, availability, and country | `Public road`, `Public`, `Germany` |
| Tariff ID | The tariff that determined the price | `79804bf6-0d6d-4e74-ae00-16c7238c4e77` |
| Voucher | The voucher group and code, if one was used | `Employee discount`, `AcmeEmployee2026` |
| Highest power drawn | The peak power reached during the session, in kW | `130.98` |
## States
A session is either ongoing or concluded:
| State | Meaning |
| - | - |
| Ongoing | The charge is in progress. `Ended at` is not set, and the session data keeps updating. |
| Concluded | The charge has finished. `Ended at` is set and a CDR has been generated. |
A CDR has no states of its own: once generated, it's immutable.
## Used in
Exchange CDRs with other networks over OCPI.
Read live and completed charging sessions programmatically.
Retrieve completed CDRs for billing and reporting.
# Payment terminals
Source: https://docs.spirii.com/components/commercial/payment-terminals
Register your terminals and attach them to the charge boxes they take payment for.
A payment terminal is a card reader at a charging site that lets a driver authorise and pay for a charge by tapping a card or phone, with no app and no account.
## Overview
In Spirii Connect, a payment terminal is the record that represents one physical terminal. It carries the terminal's identity, the merchant whose name appears on driver receipts, and the charge boxes it takes payment for. Creating the record is what makes the terminal known to the Spirii platform, so its payments and sessions land against the right charge boxes.
Two things sit behind every terminal, and you choose them separately: the hardware, and the point-of-sale (POS) software running on it. One record names both.
For how in-person payment works end to end, and which integration approach suits your hardware, see [In-person payments](/capabilities/payments/in-person-payments).
Creating the record in Connect does not register the terminal with its manufacturer, and it does not obtain a Merchant ID (MID) from a payment service provider. Both are separate steps, and both come first. See [Set up a payment terminal](/guides/payment-terminal-setup) for the order.
## Context
A payment terminal is a CPO object. You register it and manage it; drivers never see the record, only the screen in front of them.
There is no payment terminal over [roaming](/capabilities/roaming/roaming-connection). What reaches an eMSP is the site's support for in-person card payment, published as an authentication method, so a driver's app can show that tapping a card works there. The terminal itself stays on the operator's side: its serial number, its merchant, and the charge boxes it serves do not cross the boundary.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| Name | Free-text label for finding the terminal in Connect | `Munich DC Hub – kiosk 1` |
| Serial number | Identifies the physical terminal. Must match the serial registered with the manufacturer, and can be corrected in Connect after the record exists | As printed on the unit |
| POS | The point-of-sale software running on the terminal | `Spirii POS` |
| Merchant | The merchant record whose name appears on driver receipts, and the party of record for the payment | `Acme Inc.` |
| Terminal language | The language Spirii POS uses on the driver-facing screen | `German` |
| Location | The site the terminal belongs to. A terminal serves one location | `Munich DC Hub` |
| Charge boxes | The charge boxes the terminal takes payment for, one or more on that location | `DE*SPI*E00012345`, `DE*SPI*E00012346` |
Merchants are their own records in Connect, created once and then selected here, so several terminals can share one merchant.
Registering a terminal in Connect completes the payment side of the setup. The record links the terminal to the charge boxes it serves and to a merchant, so in-person payments settle correctly and reach you through Spirii's billing and payout. Operating the terminal itself — connectivity and hardware health — stays in the manufacturer's portal. That is where to look if a terminal stops taking payment, since Connect holds the terminal's configuration rather than its live state.
## Relationships
A location owns both its charge boxes and the terminals that serve them. Each terminal also points at the merchant on its receipts and the POS running on it.
### One location, several charge boxes
A terminal belongs to one location and takes payment for one or more charge boxes on it. A charge box can carry more than one terminal.
Attaching several charge boxes to one terminal is kiosk mode: a single pole-mounted or wall-mounted terminal serving a row of chargers. On a public DC hub that saves fitting a terminal to every unit, and it gives drivers one place to pay.
With Spirii POS, the driver picks the connector on the terminal screen before paying, so one terminal can cover several charge boxes without ambiguity about what is being paid for.
### A terminal is not its POS
The terminal is hardware. The POS is the software running on it, and it owns everything the driver sees. Connect keeps both on one record because you choose them independently: you can run Spirii POS on a supported terminal, or register a terminal that runs the charger manufacturer's POS or a third-party POS.
| The terminal record controls | The POS controls |
| - | - |
| Name and serial number | What the driver sees on screen, including the price and VAT rate |
| The location and charge boxes served | Connector selection |
| The merchant on driver receipts | The receipt, and the QR code that delivers it |
| How the terminal's revenue flows through billing and payout | Stopping a session from the terminal |
| | AFIR and Eichrecht compliance of the driver-facing flow |
Registering a terminal that runs another provider's POS still earns its place. The terminal is visible and managed in Connect, and its revenue flows through Spirii's billing and payout, including arrangements where Spirii is the merchant of record. What you give up is the driver-facing layer: that provider controls the screen, the receipt, and compliance for the payment flow.
Terminal language sets the Spirii POS display language. Where another provider's POS is running, that provider controls the language the driver sees.
## Used in
To register your first terminal, follow [Set up a payment terminal](/guides/payment-terminal-setup).
How Spirii POS, manufacturer, and third-party POS integrations work.
Register, configure, and go live with a terminal.
How terminal revenue reaches you, in turnkey and PAAS.
How terminal sessions appear in billing and reporting.
The units a terminal takes payment for.
The site a terminal belongs to.
# Tariffs
Source: https://docs.spirii.com/components/commercial/tariffs
How an operator sets what a driver pays to charge at a location.
A tariff defines what a driver pays to charge at a location: the price, the currency, and the conditions around it.
## Overview
A tariff is the pricing container an operator applies to one or more locations. It sets a base price (a fixed rate, or a dynamic one that follows the hourly spot price) and can layer conditional fees on top to vary the price by time of day, day of week, or how long a session has run. Every price a tariff shows a driver is gross, including VAT.
One tariff can apply to many locations, so a change to it updates the price everywhere it's bound.
## Context
A tariff sits on one side of a two-sided platform, and an operator sets two prices from it: one for Spirii's own surfaces, one for external networks.
### CPO context
You set what drivers pay. Within Spirii's own mobility surfaces — Spirii Go, branded apps, Spirii charge keys, and Spirii POS — that's the **tariff**, the full model described below. For drivers arriving from other networks, you set a separate, simpler **roaming tariff**. The attributes here describe the tariff as you build it in Spirii Connect.
### eMSP context
An external eMSP never sees your tariff. When its drivers charge at your location over roaming, it's billed your **roaming tariff**: a flat per-kWh price, net of VAT. It then adds its own margin before charging its driver. [Roaming](/capabilities/roaming/roaming-connection) covers how that price is exchanged.
## Key attributes
### Tariff
| Attribute | Description | Example |
| - | - | - |
| Name | A clear name for the tariff | `Public DC charging` |
| Currency | The currency the tariff operates in | `EUR` |
| Customer | The customer the tariff belongs to, or All Customers to share it across several | `Acme Inc.` |
| Type | Whether the base price is fixed or dynamic | `Dynamic` |
| Base fee | The fixed price, or (for a dynamic tariff) the minimum fee that applies when spot data is low or missing | `0.45 €/kWh` |
| Conditional fees | Optional fees layered on the base | `Time fee: 0.10 €/min after 180 min` |
A tariff's **base fee** is either **fixed** (a set price per kWh or per minute that doesn't change) or **dynamic** (the hourly spot price from a power grid zone, with a markup on top and a minimum fee as the fallback).
**Conditional fees** layer on top, and each is an **energy fee** (per kWh), a **time fee** (per minute), or a **flat fee** (per session). A fee can be limited to certain times and days, or set to apply only after a session has run for a while. How several fees combine is covered in [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic).
An older tariff format also exists on the platform. It serves a few legacy paths: older app versions, MobilePay in Denmark, and some embedded POS terminals. It doesn't support conditional fees. New tariffs use the format described here.
### Roaming tariff
The roaming tariff is a separate, simpler price: a single flat rate per kWh, set per location, that external eMSPs are billed when their drivers charge there over roaming. You enter it gross (including VAT for the location's country) so it's comparable with your tariff, but eMSPs receive it net.
It's selected from a list per location rather than built like a full tariff. You set it on the location's **Edit location** page in Connect; [Roaming pricing](/capabilities/pricing/pricing-options-and-logic#roaming-pricing) covers how to choose and apply one.
## Relationships
### A tariff is not the final price a roaming driver sees
Within Spirii's surfaces, the tariff is what the driver pays. Over roaming, the roaming tariff is only the price *you* charge the eMSP; the eMSP adds its own margin, so a roaming driver may see a higher price than your roaming tariff.
A voucher can also override a tariff: a driver with an active voucher pays the voucher's price instead, at the locations it covers.
## Used in
How to build a price from a base fee and conditional fees, and set a roaming tariff.
A tariff is applied to one or more locations.
How the roaming tariff reaches external networks.
A voucher can link a tariff, or override one for a user group.
# Customers
Source: https://docs.spirii.com/components/organisation/customers
The organisation an operator serves, and the boundary that controls who sees what.
A customer is an organisation, or a private individual, that sits one level below an operator on the platform: the party an operator does business with, and the owner of the records tied to it.
## Overview
An operator runs a service on the platform; a customer is who that service is *for*. Spirii's platform is built for 2 business models:
* A charge point operator (CPO) and the site owners whose locations it runs.
* An e-mobility service provider (eMSP) and the fleet owners whose drivers it serves.
Either way, the customer is the organisation one level down. It can be a business or a private individual.
Every main object in Spirii Connect (locations, tariffs, vouchers, charge keys, and more) is tied to a customer. That link is also what governs access: a Spirii Connect user sees an object when it belongs to a customer they're permitted to see. So a customer is two things at once: a record of who owns what, and the boundary that decides who can see and manage it.
## Context
A customer means something a little different depending on the operator it sits under. Either way, customers live entirely inside Spirii Connect: the operator's own structure for ownership and access, not something drivers or roaming partners see.
### CPO context
When the operator is a charge point operator, its customers are the **site owners** whose locations it runs: the businesses, municipalities, or individuals that own the sites, the chargers, and the revenue they produce. A smaller operator working under a larger one can be a customer too.
### eMSP context
When the operator is an e-mobility service provider, its customers are the **fleet owners** it serves: the organisations whose drivers charge across the network. Here a customer owns the fleet's accounts, charge keys, and access rather than physical sites.
## Key attributes
| Attribute | Description | Example |
| - | - | - |
| Name | The company name, or a person's full name for a private customer | `Acme Inc.` |
| Type | Whether the customer is a business or a private individual | `Business` |
| Country | The customer's single origin country | `Germany` |
| Owner | Who the customer sits under: the operator, or another business customer. A private customer can't own others | `Operator` |
| External ID | Your own reference for the customer, for use in internal or billing systems | `CUST-10293` |
A customer also has a contact person, and can hold billing and payout details that are used when Spirii invoices the customer.
## Relationships
### Operators and customers
An operator sits above its customers. It can see every customer beneath it, while each customer sees only what belongs to it. Operators, whether CPOs or eMSPs, are set up and managed by Spirii.
### Parent and child customers
A customer can own another customer. A parent customer can see everything belonging to its children, which mirrors real group structures: a holding company over its subsidiaries, or a head office over its regional entities.
[The customer hierarchy](/capabilities/account/customer-management#the-customer-hierarchy) covers how you build the tree, and the one rule that constrains its shape.
### A customer is not a driver
In charging, "customer" often means the person plugging in. Here it doesn't: a customer is the organisation an operator serves, either a site owner or a fleet owner. The people who actually charge are app users and drivers, tracked separately.
## Used in
Each location is owned by a customer.
A tariff is owned by a customer, or shared across all of them.
A voucher group belongs to a customer.
A fleet's charge keys are tied to a customer.
# AFIR compliance
Source: https://docs.spirii.com/developers/afir-compliance
Publish your public chargers' static and dynamic data to a National Access Point in DATEX II format.
The EU's Alternative Fuels Infrastructure Regulation (AFIR), Article 20, requires operators and owners of publicly available recharging stations to make specified static and dynamic data about their infrastructure available — free, unrestricted, and via an API. Spirii provides dedicated endpoints that return this data in DATEX II v3, ready to feed to your member state's National Access Point (NAP).
## Before you start
This playbook is for operators and owners of public charging in an AFIR member state. Each member state has its own NAP, so check its integration requirements first — in particular whether it consumes **DATEX II** (covered below) or **OCPI** (see the note at the end). You'll also want the CPO ID or customer IDs whose data you're publishing; contact your Spirii representative if you're unsure which to use.
## The DATEX II endpoints
Two endpoints return AFIR data in DATEX II v3, the exchange format most National Access Points use:
* **Static data** — `GET /v2/afir/energy-infrastructure-tables` returns infrastructure metadata: sites and stations (locations and charge boxes), refill points and connectors, operating hours, and tariff information.
* **Dynamic data** — `GET /v2/afir/energy-infrastructure-statuses` returns real-time availability and status, with tariff information.
Both are **public** — no API key — and built for a data feed: responses are gzip-encoded, and they support conditional caching, so a request with an `If-Modified-Since` header returns `304 Not Modified` when nothing has changed.
```bash theme={null}
# Static infrastructure data for your operator
curl "https://api.spirii.com/v2/afir/energy-infrastructure-tables?cpoId=42"
# Real-time status for your operator
curl "https://api.spirii.com/v2/afir/energy-infrastructure-statuses?cpoId=42"
```
Poll the statuses endpoint more often than the tables endpoint — availability changes constantly, while the infrastructure itself rarely does — and use `If-Modified-Since` on both to avoid re-fetching unchanged data.
### Filter to the data you publish
Three filters scope the response, and can be combined — when you pass more than one, only assets matching all of them are returned.
| Filter | Purpose | Example |
| - | - | - |
| `cpoId` | Narrow to a single Charge Point Operator's assets (recommended) | `?cpoId=42` |
| `customerIds` | Narrow to one or more customers, comma-separated | `?customerIds=1233,3332,553` |
| `countryIsos` | Restrict to countries, as ISO 3166-1 alpha-2 codes | `?countryIsos=DK,FR,DE` |
```bash theme={null}
curl "https://api.spirii.com/v2/afir/energy-infrastructure-tables?customerIds=1233&cpoId=42&countryIsos=DK,FR"
```
With no filter, each endpoint returns only 100 records. Always filter by your `cpoId` or `customerIds` so you publish your complete infrastructure rather than a truncated sample.
## If your NAP uses OCPI
Where a National Access Point consumes OCPI rather than DATEX II, the same AFIR-required data is available through the OCPI-formatted [Locations](https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations) endpoint, with the [Tariffs](https://docs.spirii.com/api-reference/tariffs-v2/fetches-a-single-existing-tariff) endpoint supplying the ad-hoc price breakdown (Article 20, paragraph 2(f)(3)). Unlike the DATEX II endpoints, this route uses your [API key](/developers/authentication).
## Related
The DATEX II v3 infrastructure tables endpoint.
The DATEX II v3 real-time status endpoint.
The site data behind both the DATEX II and OCPI routes.
# Authentication
Source: https://docs.spirii.com/developers/authentication
How to get access to the Spirii Public API and authorize requests.
All Spirii Public API requests must be authenticated. The API uses **bearer tokens** sent in the `Authorization` header.
## Create an API key
Create an API key via Spirii Connect. Navigate to [API tokens](https://connect.spirii.com/team?activeTab=api_tokens\&limit=24\&page=1) under Team Access.
Upon creation, you will receive your unique API key via a secure one-time link. This link can only be opened once, so ensure you store your key securely after accessing it.
Only Spirii Connect users with an **Operator** role or higher can create API tokens.
## Authorize a request
Send the key in the `Authorization` header, prefixed with `Bearer`:
```http theme={null}
Authorization: Bearer YOUR_API_KEY
```
## Security best practices
Treat API keys like passwords. Never commit them to source control or embed them in mobile apps or front-end bundles.
* Store keys in a secret manager or environment variables — never in code.
* Rotate keys regularly. To rotate without downtime: provision a new key, roll it into your application, then revoke the old one.
* Restrict outbound calls to the Spirii API to known IP ranges where possible.
# Conventions
Source: https://docs.spirii.com/developers/conventions
The rules every Spirii API endpoint shares — base URL, versioning, methods, and data formats.
A handful of conventions hold across every endpoint in the Spirii API. Learn them once and you can read any endpoint's reference without relearning the basics.
## Base URL and format
All requests go to the production API:
```
https://api.spirii.com
```
Requests and responses are JSON (`application/json`).
## Versioning
The major version is part of the path — current endpoints sit under `/v2`:
```
https://api.spirii.com/v2/chargeboxes
```
See [Versioning](/developers/versioning) for the current version and how changes are managed. The earlier Spirii legacy API remains available for existing integrations; new work should use the current version.
## Authentication
Every request is authenticated with an API key, sent as a bearer token in the `Authorization` header. See [Authentication](/developers/authentication) for how to create and send it.
## Methods
The API follows REST conventions:
| Method | Use | Success |
| - | - | - |
| `GET` | Read a resource or list resources | `200` |
| `POST` | Create a resource | `201` |
| `PATCH` | Update a resource — send only the fields you're changing | `200` |
| `DELETE` | Remove a resource | `200` |
A resource's ID goes in the path, for example `PATCH /v2/tokens/{id}`.
## Naming and casing
Property names and query parameters are **camelCase** — `nextPageCursor`, `locationIds`, `startedAt`.
Enum values are the exception: their casing varies between fields, so copy each value exactly as the endpoint's reference lists it rather than assuming a style.
## Data formats
* **Timestamps** are ISO 8601, in UTC — `2025-12-31T23:59:59.999Z`. Parse them with a standard date-time parser rather than by hand.
* **Numbers** are JSON numbers with a dot decimal separator, such as `100.5`. This is the wire format, distinct from how a value is displayed to a person.
* **Money** is a numeric amount alongside an ISO 4217 `currency` code — `EUR`, not a symbol.
* **Quantities** are numeric, with the unit given in the field's description — energy in kWh, power in kW, current in A, voltage in V, durations in seconds.
* **Identifiers** are numbers or strings depending on the resource, and several encode structured information. See [Identifiers](/developers/identifiers) for the formats and what they mean.
## Null and optional fields
Optional values may come back as `null` or be left out of the response entirely. Some fields are returned only when you request them. Treat the reference for each field as the source of truth.
Where this page and an endpoint's reference disagree, the reference is authoritative for that endpoint.
## Related
Create and send your API key.
The current version and how changes are managed.
The ID formats each resource uses.
Page through list results.
Narrow and sort list results.
Status codes and how to handle them.
# CRM integration
Source: https://docs.spirii.com/developers/crm-integration
Keep your CRM and Spirii in step on every account — who the customer is, what they run or charge with, and what their charging is worth.
By the end of this playbook your CRM and Spirii will share one view of each customer account: its identity and structure, maintained from your CRM, and the locations, charge keys, drivers, and charging activity behind it, pulled back from Spirii.
## Before you start
This playbook is for operators and e-mobility providers who run their customer relationships in a CRM and want it to reflect what happens on the Spirii platform. You'll need an [API key](/developers/authentication) and a working understanding of [customers](/components/organisation/customers), which are the accounts everything in this playbook hangs off.
The app user steps apply only if you have a branded app. Without one, skip them.
## How the pieces fit
In Spirii, a **customer** is the account: the organisation you do business with. What hangs off it depends on which side of your business the account sits on, and most partners have accounts on both.
* **On your charging network**, a customer is a site owner. Its **locations** and the chargers on them belong to it, and its charging activity is the revenue earned on those locations.
* **For your drivers**, a customer is a fleet. Its **charge keys** belong to it, and its charging activity is what those charge keys consumed, on your network and on others. In the API, charge keys are `/v2/tokens`.
* **App users** are the drivers signed up to your branded app. A driver can hold charge keys and be associated with a customer.
```mermaid theme={null}
flowchart TD
C("Customer") --> CH("Child customers")
C --> L("Locations")
C --> K("Charge keys")
L -->|"CDRs in cpo mode"| R("Charging activity")
K -->|"CDRs in emp mode"| R
AU("App users") --> K
```
Fields named `crmId` and `crmCustomerId` in the Spirii API hold **Spirii's** customer ID, not your CRM's. Store your CRM's account ID in the customer's `externalId`, and treat any `crm…` field as a Spirii reference.
### Decide which system owns each record
A two-way sync works when each record has one system of record. If both systems can edit the same field, a change in one gets overwritten by the next sync from the other, and neither team can tell which value is current.
| Record | System of record | Sync direction | Endpoints |
| - | - | - | - |
| Customer identity: name, type, country, contact, parent, `externalId` | Your CRM | CRM → Spirii, and changes back | [Create](https://docs.spirii.com/api-reference/customer-v2/create-a-new-customer), [update](https://docs.spirii.com/api-reference/customer-v2/update-a-customer), [list](https://docs.spirii.com/api-reference/customer-v2/get-v2customers) |
| Locations and chargers | Spirii | Spirii → CRM | [Locations](https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations) |
| Charge keys | Spirii | Spirii → CRM | [Charge keys](https://docs.spirii.com/api-reference/tokens/get-a-list-of-tokens) |
| App users | Spirii — drivers create them by signing up | Spirii → CRM | [App users](https://docs.spirii.com/api-reference/app-users/get-a-list-of-app-users) |
| Charging activity | Spirii | Spirii → CRM, aggregated | [CDRs](https://docs.spirii.com/api-reference/charge-records-v2/get-a-list-of-cdrs) |
Leave billing and payout details (bank details, billing settings, financial setup) out of the sync. They drive Spirii's invoicing and payouts, and belong to your finance process rather than your CRM.
## Set up the sync
A CPO running charging operations for 100 site owners is a typical case: each site owner is an account in the CRM and a customer in Spirii, and account managers want each account's sites, chargers, and monthly revenue next to the contract.
For each existing customer, find it in Spirii and write your CRM's account ID into `externalId`. The `search` parameter matches customer names and IDs, including `externalId`.
```bash theme={null}
curl "https://api.spirii.com/v2/customers?search=Lindenhof" \
-H "Authorization: Bearer "
curl -X PUT https://api.spirii.com/v2/customers/123 \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{ "externalId": "ACC-100482" }'
```
Once every customer carries an `externalId`, you can match records in both directions without relying on names.
When an account is won in the CRM, create the customer in Spirii. `name`, `type`, `country`, `contactDetails`, and `ownerId` are required. `ownerId` places the customer in the hierarchy: your own customer ID for a direct account, or a parent customer's ID for a subsidiary.
```bash theme={null}
curl -X POST https://api.spirii.com/v2/customers \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"name": "Lindenhof Housing",
"type": "Business",
"ownerId": 234,
"externalId": "ACC-100482",
"country": "DE",
"contactDetails": { "name": "Facilities Team", "email": "facilities@example.com", "phone": "+4930123456" }
}'
```
Store the returned `id` on the CRM account. It's the ID you'll filter locations, charge keys, and CDRs by. See [Customer management](/capabilities/account/customer-management) for how the hierarchy is structured.
When a field your CRM owns changes, send it with an update. The update accepts any subset of the customer's fields, so there's no need to resend the whole record.
```bash theme={null}
curl -X PUT https://api.spirii.com/v2/customers/123 \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{ "contactDetails": { "name": "Anna Keller", "email": "a.keller@example.com" } }'
```
Customers can also be edited in Spirii Connect. Fetch the ones updated since your last sync and reconcile them against the CRM. Setting `updatedAtFrom` sorts results by `updatedAt`, oldest first.
```bash theme={null}
curl "https://api.spirii.com/v2/customers?updatedAtFrom=2026-09-27T00:00:00.000Z&limit=50&offset=0" \
-H "Authorization: Bearer "
```
This endpoint pages by `offset`. Increase it by `limit` until a page comes back short.
Pull each account's operational footprint onto the CRM record: its locations and their EVSEs on the network side, and its active charge keys on the driver side.
```bash theme={null}
curl "https://api.spirii.com/v2/locations?customerIds=123&limit=100" \
-H "Authorization: Bearer "
curl "https://api.spirii.com/v2/tokens?customerId=123&isActive=true" \
-H "Authorization: Bearer "
```
See the [Locations](/components/charging/locations) and [Charge keys](/components/access/charge-keys) components for what each record holds.
If you have a branded app, list its app users to keep driver contacts in the CRM. Each record carries the driver's name, email, phone number, the customer they're associated with, and their charge keys.
`newsletter` records whether the driver opted in to marketing email when they signed up. Use it as the consent flag for marketing to that driver from your CRM.
See the [App users](/components/access/app-users) component for who can see an app user and how deletion works.
Summarise each account's charging from its CDRs. Which mode and filter you use depends on the side of the business the account sits on:
| Account | `mode` | Filter CDRs on | What you get |
| - | - | - | - |
| Site owner | `cpo` | `location.crmCustomerId` | Sessions on the customer's locations |
| Fleet | `emp` | `auth.idTag.crmCustomerId` | Sessions on the customer's charge keys, on any network |
```bash theme={null}
curl -G "https://api.spirii.com/v2/charge-records" \
-H "Authorization: Bearer " \
--data-urlencode 'mode=cpo' \
--data-urlencode 'filter={"location.crmCustomerId":{"$eq":123}}' \
--data-urlencode 'updatedAtFrom=2026-09-01T00:00:00.000Z' \
--data-urlencode 'limit=5000'
```
Add `includeChildCompanyRecords=1` to include sessions belonging to the customer's direct children. Sum `consumed` and `price.amountExVat` per account and period for the CRM record. The [Reporting and dashboards](/developers/reporting-and-dashboards) playbook covers storing and aggregating CDRs.
## Verify
Create a test account in your CRM and let the sync run. The customer appears under **Customer management** in Spirii Connect with your CRM's account ID as its external ID. On the next pull it comes back matched to the same CRM account, with no duplicate created.
## Schedule the sync
Not every resource can be fetched by what changed, so the schedule differs per resource.
| Resource | Fetch what changed? | How to keep it current |
| - | - | - |
| Customers | Yes, `updatedAtFrom` / `updatedAtTo` | Incremental pull |
| CDRs | Yes, `updatedAtFrom` / `updatedAtTo` | Incremental pull |
| Charge keys | Sortable by `updatedAt`, not filterable | Sort by `updatedAt` descending and stop once you reach records older than your last sync |
| Locations | No time filter | Full refresh, scoped with `customerIds` |
| App users | Filterable by `createdAt` only | Full refresh; treat an app user missing from the result as removed |
Full refreshes count against the [rate limit](/developers/rate-limits) of 120 requests per minute. Size their schedule to the number of accounts: a network with thousands of locations can't refresh them every few minutes.
## Best practices
* **Match on IDs, never names.** Join on Spirii's customer `id` and your `externalId`. Names change and aren't unique. See [Identifiers](/developers/identifiers).
* **Page each endpoint the way it pages.** Customers, charge keys, and app users use `offset`; locations and CDRs use cursors. Default page sizes also differ, so set `limit` explicitly. See [Pagination](/developers/pagination).
* **Request only what the CRM needs.** Some driver fields on CDRs are personal data and are returned only with sufficient access. Use `fields` on CDR requests to keep payloads small.
* **Retry transient errors safely**, and don't retry a rejected request unchanged. See [Errors](/developers/errors).
## Next steps
Turn the same accounts' CDRs into invoice lines and ledger entries.
The retrieval patterns for storing and aggregating CDRs.
# ERP integration
Source: https://docs.spirii.com/developers/erp-integration
Invoice your customers, and post charging costs and home charging reimbursements, from Spirii's charge detail records.
By the end of this playbook you'll turn Spirii's charge detail records (CDRs) into invoice lines and ledger entries in your ERP, matched to the right customer, site, and cost centre. If you run home charging reimbursement through payroll, you'll bring approved expense reports in as well.
## Before you start
This playbook is for operators and e-mobility providers who invoice their customers from their own systems. That's the case on the **Invoice Data Service** and **No service** billing service levels. On **Full Service**, Spirii invoices your customers for you, so your ERP receives Spirii's invoices rather than building its own. See [Billing service levels](/capabilities/billing-payouts/charge-key-billing#billing-service-levels).
Spirii doesn't expose finished billing documents through the API. You build invoice lines from raw CDRs, which carry the energy, price, VAT rate, and references each line needs.
You'll need an [API key](/developers/authentication) and a working understanding of [sessions and CDRs](/components/charging/sessions-and-cdrs). Who carries the VAT on a session depends on who is the merchant; see [Who is the merchant](/capabilities/billing-payouts/billing-and-payout-flows#who-is-the-merchant).
## How the pieces fit
Each CDR becomes one line. Three references on it place that line in your ERP:
* **The customer**, to know whom to invoice. The CDR carries Spirii's customer ID, which you map to your ERP's customer number through the customer's `externalId`.
* **The charge key's billing reference**, such as a driver's cost centre. It travels on the CDR as `auth.idTag.billingReference`.
* **The location's billing reference**, such as a site or project code. It isn't on the CDR: fetch it from the location, using the CDR's `location.id`.
```mermaid theme={null}
flowchart LR
CDR("CDR") -->|"location.crmCustomerId or auth.idTag.crmCustomerId"| CU("Customer: externalId")
CDR -->|"auth.idTag.billingReference"| CK("Charge key reference")
CDR -->|"location.id"| LO("Location: billingReference")
CU --> LINE("Invoice line in your ERP")
CK --> LINE
LO --> LINE
```
### Choose the mode for what you invoice
| You're invoicing | `mode` | Match each CDR to a customer on |
| - | - | - |
| Charging on locations you operate | `cpo` | `location.crmCustomerId` |
| Charging on the charge keys you issued, on any network | `emp` | `auth.idTag.crmCustomerId` |
If you do both, run the two as separate pulls and keep the lines apart in your ERP.
## Set up invoicing
A fleet operator with 600 issued charge keys is a typical case: each key's billing reference holds the driver's cost centre, and every month's charging, at the depot and on the road, is posted to the ERP per cost centre.
Set each customer's `externalId` to its customer number in your ERP, so a CDR's customer resolves to an ERP account without a lookup table. If a CRM owns your customer records, the [CRM integration](/developers/crm-integration) playbook covers keeping `externalId` in step.
Write the references your invoices need onto charge keys and locations. Both are free-text fields.
```bash theme={null}
curl -X PATCH https://api.spirii.com/v2/tokens/48213 \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{ "billingReference": "CC-4410" }'
curl -X PATCH https://api.spirii.com/v2/locations/12345 \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{ "billingReference": "SITE-0231" }'
```
Fetch CDRs by `updatedAt`, in the mode that matches what you invoice. To invoice one customer, add a filter on its customer ID.
```bash theme={null}
curl -G "https://api.spirii.com/v2/charge-records" \
-H "Authorization: Bearer " \
--data-urlencode 'mode=emp' \
--data-urlencode 'filter={"auth.idTag.crmCustomerId":{"$eq":123}}' \
--data-urlencode 'updatedAtFrom=2026-09-01T00:00:00.000Z' \
--data-urlencode 'updatedAtTo=2026-10-01T00:00:00.000Z' \
--data-urlencode 'limit=5000'
```
Store what you pull, and decide which timestamp assigns a session to an invoice period, such as `endedAt`. Apply that choice everywhere so a session never lands in two periods.
Keep CDRs whose `paymentMethod` is `Invoice`. Sessions paid another way, in an app, at a payment terminal, or through a roaming partner, have already been paid for, and invoicing them again would charge twice.
The `filter` parameter doesn't accept `paymentMethod`, so apply this rule after you've pulled the records. Sessions with `paymentMethod` `Free` are yours to decide on, depending on how you charge for them.
Group the kept CDRs by customer and `price.currency`, and within that by `price.vatRate`. For each line, take:
| Line field | From the CDR |
| - | - |
| Quantity | `consumed` (kWh) |
| Net amount | `price.amountExVat` |
| VAT rate | `price.vatRate`, as a fraction: `0.25` is 25% |
| Gross amount | `price.amount` |
| Cost centre | `auth.idTag.billingReference` |
| Site reference | The location's `billingReference`, looked up by `location.id` |
| Driver or vehicle | `auth.idTag.label` |
| Traceability | `transactionId` |
Use the amounts on the CDR rather than recalculating them from the tariff. `price.breakdown` shows how a price was arrived at, if a customer asks.
## Verify
Build lines for one customer and one closed month, then export that customer's CDRs for the same month from **Charge detail records** in Spirii Connect. The session count, total kWh, and net amount match your ERP's lines once you apply the same `paymentMethod` rule to the export.
## Handle corrected CDRs
A CDR can change after you first pull it. When a faulty session's price is corrected, the record is recalculated and its `updatedAt` moves. Keep pulling by `updatedAt` after a period closes, compare against what you've already invoiced, and raise the difference as a credit or adjustment in your ERP rather than editing an issued invoice.
## Home charging reimbursement
If employees are reimbursed for home charging through payroll, the ERP that runs payroll picks up each month's approved expense report. See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) for how reports are produced and approved.
The Reimbursement API authenticates with the same API key, from its own base URL: `https://api.spirii.com/reimbursement`.
Filter by status, and by fleet customer if you handle more than one.
```bash theme={null}
curl "https://api.spirii.com/reimbursement/v1/expense-reports?status=Approved&customerCrmId=4567&limit=100" \
-H "Authorization: Bearer "
```
| Status | Means |
| - | - |
| `Active` | The current month, still collecting sessions |
| `Pending` | Ready for approval |
| `Approved` | Approved and ready for payroll |
| `FundsReceived` | Approved and paid |
Fetch the report to get its expenses, one per employee. `recipientExternalId` is the `externalId` on the employee's customer record, which makes it the key to your payroll system. `amountInCents` is the amount to pay and `currency` its currency.
For the report as a file, download it with `format=csv` or `format=pdf` from [Download expense report](https://docs.spirii.com/api-reference/reimbursement-expenses/download-expense-report).
A report can be approved either in Spirii Connect or with [Approve expense report](https://docs.spirii.com/api-reference/reimbursement-expenses/approve-expense-report). Approving through the API stores the report and notifies its email recipients, so approve only once the fleet manager has checked it.
## Best practices
* **Mind the units.** The Reimbursement API returns amounts in cents and energy in watt-hours. CDRs use decimal amounts and kilowatt-hours. Convert before combining the two.
* **Keep `transactionId` on every line.** It traces a line back to the session behind it when a customer queries an invoice.
* **Store CDRs locally.** A CDR request returns at most 5,000 records and the API allows 120 requests per minute. Pull incrementally and build invoices from your own copy. See [Rate limits](/developers/rate-limits).
* **Page through completely.** CDRs page by cursor; follow it to the end. See [Pagination](/developers/pagination).
* **Split by currency.** A customer charging in several countries can produce sessions in more than one currency. Invoice each currency separately rather than converting.
## Next steps
Keep the customer records these invoices depend on in step with your CRM.
The retrieval patterns for storing and aggregating CDRs.
# Errors
Source: https://docs.spirii.com/developers/errors
The HTTP status codes the API returns, what they mean, and how to handle them.
The Spirii API uses standard HTTP status codes to signal the outcome of a request. A `2xx` status means the request succeeded. A `4xx` means something about the request needs fixing before it will work. A `5xx` means the request was valid, but Spirii couldn't complete it.
## Status codes
These are the codes you'll meet across the API. Each endpoint's reference page lists the specific codes it can return — a `404`, for instance, appears only where the request references a resource that might not exist.
| Status | Meaning | What to do |
| - | - | - |
| `200` OK / `201` Created | The request succeeded | Continue |
| `400` Bad Request | The request was malformed or failed validation | Fix the request using the message in the response |
| `401` Unauthorized | The request isn't authenticated — the API key is missing, invalid, or expired | Check the `Authorization` header and your API key |
| `403` Forbidden | The request is authenticated but not allowed to perform this action | Check that your key has access to the resource |
| `404` Not Found | The resource — or a resource referenced in the request — doesn't exist | Check the ID or path |
| `409` Conflict | The request conflicts with the current state — the resource already exists, or is already in the state you're asking for | Check the current state; the change may already be applied |
| `422` Unprocessable Entity | The request was well-formed but broke a business rule | Fix the request using the message in the response |
| `500` Internal Server Error | Something failed on Spirii's side | Retry with backoff; if it persists, contact support |
| `502` Bad Gateway | A transient upstream error | Retry with backoff |
`401` and `403` both signal an access problem: `401` when a request isn't authenticated, `403` when it's authenticated but not permitted. Usage isn't fully consistent across the API — some endpoints return `403` for an authentication failure — so treat either as an access issue, check your key and its permissions, and read the endpoint's reference for the codes it returns. See [Authentication](/developers/authentication) for how to send the key correctly.
## Error responses
An error response carries the status code and a human-readable message describing what went wrong.
Read the **status code** to decide what your integration does next, and surface the **message** to whoever is operating the integration. Treat the message as descriptive text for a person, not a stable field to branch on in code — the status code is the contract.
## Handling errors
How you respond depends on the class of error:
* **`4xx` — fix the request.** A validation error, a missing resource, or an auth problem won't resolve on its own. Don't retry the same request unchanged; correct it first. A `409` is the exception: the request may be valid but the resource is already in the target state, so read the current state before deciding whether to retry.
* **`5xx` — retry with backoff.** A `500` or `502` is usually transient. Retry with exponential backoff and a ceiling on attempts rather than looping immediately.
* **Rate limiting.** Requests beyond the limit are rejected. Back off and retry, and see [Rate limits](/developers/rate-limits) for the current limit and how to stay under it.
Retrying is safe for reads. For writes, a `5xx` doesn't tell you whether the change applied — check the resource's state before retrying a create or update, so you don't duplicate it.
## Related
Authenticate your requests correctly to avoid `401` and `403` responses.
Stay within the request limit.
The status codes each endpoint can return.
# Filtering
Source: https://docs.spirii.com/developers/filtering
Narrow, search, and sort list results with query parameters, and how the available filters differ by endpoint.
List endpoints accept query parameters that narrow the results to the records you want — by identifier, by type, by date, and more. Which filters an endpoint offers differs from endpoint to endpoint, so each endpoint's reference page is the source of truth for what it accepts.
## How filtering works
Filters are query parameters on a list request. Combine several to narrow the results further:
```bash theme={null}
curl "https://api.spirii.com/v2/transactions?locationId=12345&transactionType=nonRoaming" \
-H "Authorization: Bearer "
```
Values follow the endpoint's schema: enums must match the reference exactly and are case-sensitive, IDs are numbers or strings, and timestamps are ISO 8601. Filtering pairs with [pagination](/developers/pagination) — the filters decide *which* records are returned, and pagination controls how you page through them.
## Common filter patterns
The same families of filter recur across the API. The parameter names and accepted values are endpoint-specific, but the shapes below are what you'll meet.
### By identifier
Return only the records matching one or more IDs. Some endpoints take a single value:
```
/v2/transactions?locationId=12345
```
Others take a list — repeat the parameter once per value (confirm the exact form on the endpoint's reference page):
```
/v2/chargeboxes?locationIds=12345&locationIds=67890
```
### By type or status
Enum filters restrict results to a fixed set of values, such as a transaction type (`nonRoaming`, `roamingCpo`) or a location type (`PublicRoad`, `Residential`). Match the value exactly as the reference lists it.
### Flags
Boolean filters toggle a subset on or off — for example `ongoing` for transactions still in progress, or `isActive` for active charge keys:
```
/v2/tokens?isActive=true
```
### Date and time ranges
Filter by a timestamp to return records from — or up to — a point in time, using ISO 8601:
```bash theme={null}
curl "https://api.spirii.com/v2/transactions?startedAt=2025-01-01T00:00:00.000Z&endedAtMax=2025-01-31T23:59:59.000Z" \
-H "Authorization: Bearer "
```
On some endpoints, applying a date filter also sets the default sort order — check the parameter's description in the reference.
### Search
Where an endpoint supports free-text search, a `search` parameter matches across a few fields at once. On charge keys, for example, it matches the charge key ID, label, or UID:
```
/v2/tokens?search=DK.SPI
```
### Sorting
A `sortBy` parameter chooses the field to order by. Some endpoints add a separate `sortDirection` (`asc` or `desc`); others fix the direction:
```
/v2/tokens?sortBy=createdAt&sortDirection=desc
```
## Filters vary by endpoint
The reference for each endpoint lists its exact filters — treat it as authoritative. A few differences are worth checking before you depend on a filter across several endpoints:
* **One value or a list.** The same idea appears as a single `locationId` on one endpoint and a `locationIds` list on another.
* **Flag values.** Most flags are `true` / `false`, but a few take `0` / `1`.
* **Date-range naming.** The lower bound is usually named for the field (`startedAt`, `validFrom`); the upper bound is named less consistently (`endedAtMax`, for instance). Read both ends off the reference rather than assuming a pattern.
* **Sorting.** Whether you can set the direction — and the default when you don't — depends on the endpoint.
* **Deprecated filters.** Where the reference marks a parameter deprecated, prefer the current one it points to (for example `customerIds` in place of `customerId`).
If your integration filters across several endpoints, read each filter off its reference page rather than reusing a name that worked elsewhere. The families are consistent; the exact parameters are not.
## Related
Page through filtered results reliably.
The exact filters each endpoint accepts.
# Fleet management integration
Source: https://docs.spirii.com/developers/fleet-management
Provision a fleet's drivers, vehicles, and accounts, then track their charging through the API.
By the end of this playbook you'll know how to set a fleet up on Spirii from your own system — its accounts, drivers, and vehicles — and how to pull the charging data back to power route planning, cost control, and reporting.
## Before you start
This playbook is for fleet management and telematics platforms integrating with Spirii. You'll need an [API key](/developers/authentication) — created by an operator in Spirii Connect, it grants access to every endpoint you'll use here — and a working understanding of [charge keys](/components/access/charge-keys), which are how drivers and vehicles authenticate to charge.
## How the pieces fit
Two objects carry a fleet integration, and it helps to hold them in mind before you start:
* A **customer** is an account you bill — a sub-fleet, department, or cost centre.
* A **charge key** is how a driver (an app or RFID) or a vehicle (Autocharge) authenticates to charge. Registering a charge key grants it access to charge; each charge key is linked to the customer that should be billed.
Once drivers and vehicles start charging, each session becomes a transaction and then a CDR, carrying the charge key and customer, so you can attribute every kWh back to a driver, vehicle, or sub-fleet.
In the API these are **tokens** — `/v2/tokens` and `/v2/token-groups`. The docs call them charge keys to match Spirii Connect; the object is the same.
If a depot is a public location and you want to keep it to your fleet, a charge key group can restrict charging there to a chosen set of charge keys — but for a private depot the charge key alone is enough, so it isn't part of the setup below.
## Set up the fleet
Create a customer for each account you bill separately. Set its `type` (usually `Business`), the parent account via `ownerId`, and an `externalId` that maps it to the account in your own system.
```bash theme={null}
curl -X POST https://api.spirii.com/v2/customers \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Logistics — North depot",
"type": "Business",
"ownerId": 234,
"externalId": "CU-12345",
"country": "DE",
"contactDetails": { "name": "Fleet Admin", "email": "fleet@example.com" }
}'
```
See [Create a customer](https://docs.spirii.com/api-reference/customer-v2/create-a-new-customer) for the billing and financial fields to include if you use Spirii's financial services.
A fleet usually already has the means to charge — RFID charge cards, or fuel cards with an RFID chip that can be repurposed for charging. Creating a charge key in the platform registers that credential so Spirii recognises it and authenticates charging against it. You'll typically:
* **register RFID charge keys** the fleet already holds, by their chip UID,
* **create virtual charge keys** for drivers authenticating through an app,
* **register vehicle (Autocharge) charge keys** by a vehicle's MAC address or VIN.
Link each charge key to the customer that should be billed with `customerId`.
```bash theme={null}
curl -X POST https://api.spirii.com/v2/tokens \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"customerId": 123,
"identifier": { "type": "rfid", "uid": "A7E942F1C8D036B5A429", "label": "VAN-07" }
}'
```
See [Create a charge key](https://docs.spirii.com/api-reference/tokens/create-a-new-token) and the [Charge keys](/components/access/charge-keys) component for the three charge key types and their fields.
## Verify
Have a provisioned charge key start a charge at the depot. The session appears in [Transactions](https://docs.spirii.com/api-reference/transactions-v2/get-a-list-of-transactions), and once it ends a CDR is generated carrying that charge key and its customer — confirming both access and billing attribution are set up correctly.
## Track charging
Once the fleet is charging, the API gives you both a live view and a settled record. The generic retrieval mechanics — paging, incremental sync, and the rate and record limits — are covered in the [Reporting and dashboards](/developers/reporting-and-dashboards) playbook; below is what matters for a fleet, starting with the live view, which is where this integration earns its keep.
### Live sessions and state of charge
The live session feed is the most valuable one for a fleet. [Transactions](https://docs.spirii.com/api-reference/transactions-v2/get-a-list-of-transactions) lists sessions in progress and recently finished, so you can see which vehicles are charging right now, how much they've drawn so far, and, on DC chargers, the vehicle's reported state of charge, which tells you when it will be ready to leave. Filter to a charge key to follow a single driver or vehicle in real time.
Feed this into dispatch, route planning, and live operations dashboards: a vehicle's charge level and expected ready time are exactly what a fleet system needs to plan the next leg.
### Depot status
Poll [Locations](https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations) for depot capacity and live EVSE and connector status — which bays are free, which are faulted — to plan charging windows and routing. See the [Locations](/components/charging/locations) component.
### Completed sessions
Each finished session becomes a CDR carrying the charge key and customer, so you can attribute cost and consumption to a driver, vehicle, or sub-fleet. Filter by the charge key or customer, then use the [Reporting and dashboards](/developers/reporting-and-dashboards) playbook to turn CDRs into reports. See the [Sessions and CDRs](/components/charging/sessions-and-cdrs) component.
## Best practices
* **Map your own IDs.** Set `externalId` on customers and a recognisable `label` on charge keys, and join on `location.id` and `evseId` when reconciling with your system. See [Identifiers](/developers/identifiers).
* **Sync incrementally and page fully.** Pull only what changed and follow the cursor to the end, so a scheduled sync moves the new records rather than re-pulling the whole history each run. See [Filtering](/developers/filtering) and [Pagination](/developers/pagination).
* **Retry transient errors safely**, and don't retry a rejected request unchanged. See [Errors](/developers/errors).
When a driver or vehicle leaves the fleet, **disable** the charge key to stop it charging. **Deleting** a charge key sets it inactive permanently — and its UID can't be reused for a new charge key — so reserve deletion for cases where you're sure.
## Next steps
The retrieval patterns for turning charging data into reports.
Set up the price pylon integration.
# Identifiers
Source: https://docs.spirii.com/developers/identifiers
The IDs each resource carries, which one to use when, and what the formatted ones encode.
Most resources in the Spirii API carry more than one identifier: an internal ID you use to address the resource, and often a formatted identifier that follows an e-mobility standard. Knowing which is which avoids a common class of integration error.
## Two kinds of identifier
**Internal IDs** are numbers the platform assigns. You use them to address a resource in a request and to link one resource to another. A charge key's `id`, the `locationId` on a charge box, the `customerId` on a charge key — these are all internal IDs.
**Standard identifiers** are strings that follow e-mobility standards. They identify things across the wider charging network — for display in apps, for roaming, and for operations at the physical charger — rather than for addressing resources in the API. An EVSE ID and a charge box's CBID are standard identifiers.
The practical rule: to call the API, reach for the numeric `id`. The formatted identifiers belong to the charging domain.
## Internal IDs
| Identifier | Identifies | Example |
| - | - | - |
| `id` | The resource itself | `12345` |
| `locationId`, `chargeBoxId`, `customerId`, `appUserId`, `voucherId`, `tokenGroupIds` | A related resource, by its `id` | `123` |
A resource's `id` goes in the path — `GET /v2/tokens/{id}` — and appears on other resources as a typed reference (`locationId`, `customerId`, and so on) to link the two.
## Standard identifiers
| Identifier | Identifies | Format | Example |
| - | - | - | - |
| CBID (`chargeBoxIdentity`) | A charge box | eMI3-style string; operator-facing | `DE*SPI*E00012345` |
| EVSE ID (`evseId`) | An EVSE | eMI3-compliant string, derived from the CBID | `DE*SPI*E00012345` |
| Connector ID | A connector on an EVSE | The EVSE ID with the connector number appended | `DE*SPI*E00012345*1` |
| Charge key UID (`uid`) | The credential a charger reads to authorise | String; the form depends on the charge key type | An RFID chip UID, a 20-character virtual UID, or a vehicle MAC/VIN |
| Party ID (`partyId`) | The operating CPO, for roaming | Party code, paired with an ISO 3166-1 country code | `SPI` (`DK`) |
The CBID is what an operator works with, and it seeds the IDs of the EVSEs on the box — so an EVSE's ID follows from its charge box rather than being assigned separately. See [Charge boxes](/components/charging/charge-boxes) and [EVSEs](/components/charging/evses-and-connectors) for how the format is built.
An EVSE also has an internal numeric `uid` alongside its `evseId` string. The `uid` is the platform's internal reference; the `evseId` is the standard identifier drivers and roaming partners see.
## Charge key IDs: id, uid, and label
In the API these are **tokens** — `/v2/tokens` and `/v2/token-groups`. The docs call them charge keys to match Spirii Connect; the object is the same.
A charge key carries three identifiers, and they're often confused:
* **`id`** — the numeric internal ID. Use it to fetch or update the charge key in the API.
* **`uid`** — the credential the charger actually reads to authorise a session (the RFID chip's value, the virtual charge key's generated string, or the vehicle's MAC/VIN).
* **`label`** — a human-facing name for recognising the charge key, such as `DK.SPI.V03198`. It's for people, not for lookups.
## Tariff IDs vary by type
A tariff reference isn't a single format. Depending on the kind of tariff, the same `id` field can be:
* a **UUID** for a standard tariff — `79804bf6-0d6d-4e74-ae00-16c7238c4e77`
* a **`SPI-` prefixed string** for a roaming product — `SPI-123`
* a **number** for a legacy tariff
Read the accompanying `type` to know which you're dealing with before you rely on the `id`'s shape.
## Related
Where the CBID comes from, and how it seeds EVSE IDs.
The EVSE ID and connector ID format.
The shared rules every endpoint follows.
The identifiers each endpoint accepts and returns.
# Spirii Developers
Source: https://docs.spirii.com/developers/introduction
Learn how to build the future of eMobility.
Find extensive documentation and guides on how to connect your business with Spirii's scalable EV charging technology. Through our APIs, Spirii shares our platform capabilities with you to unlock integrations that fit your exact use case.
Seamlessly connect your backend systems, take control of the charging experience, and integrate with your business ecosystem, leveraging the full potential of the EV charging ecosystem.
Make your first authenticated request against the Spirii Public API.
Browse every endpoint, with examples and request/response schemas.
# Pagination
Source: https://docs.spirii.com/developers/pagination
How list endpoints return results in pages, and how to retrieve every result reliably.
List endpoints return results in pages rather than all at once. Cursor-based pagination is the standard across the Spirii API; some existing endpoints use offset-based pagination instead. An endpoint's reference page lists the exact parameters it accepts, so that is always the source of truth for how a given endpoint pages.
## Cursor pagination
The standard. You request a page, and the response hands you a cursor pointing at the next one. You keep following cursors until there are none left.
**Request parameters**
| Parameter | Description | Default |
| - | - | - |
| `limit` | Number of records to return, from 1 to 100 | `25` |
| `nextPageCursor` | Cursor returned by a previous response, to fetch the next page | — |
| `previousPageCursor` | Cursor returned by a previous response, to fetch the previous page | — |
**Response shape**
```json theme={null}
{
"data": [ /* the records for this page */ ],
"nextPageCursor": "My0xMDAw",
"previousPageCursor": null
}
```
The cursors are opaque strings — don't parse or build them, only pass back what you received. When there are no further results, `nextPageCursor` comes back empty.
### Page through every result
Request the first page, then keep passing the returned `nextPageCursor` back until it's empty:
```bash theme={null}
# First page
curl https://api.spirii.com/v2/chargeboxes?limit=100 \
-H "Authorization: Bearer "
# Next page — pass the nextPageCursor from the previous response
curl "https://api.spirii.com/v2/chargeboxes?limit=100&nextPageCursor=My0xMDAw" \
-H "Authorization: Bearer "
```
In code, loop until the cursor runs out:
```javascript theme={null}
async function fetchAll() {
const results = [];
let cursor;
do {
const url = new URL("https://api.spirii.com/v2/chargeboxes");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("nextPageCursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${SPIRII_API_KEY}` },
});
const body = await res.json();
results.push(...body.data);
cursor = body.nextPageCursor;
} while (cursor);
return results;
}
```
Cursor responses don't include a total count, so you can't show "page 3 of 20" or jump to an arbitrary page. You page forward (or back) until the cursor is empty. This keeps paging stable even while records are being added or removed underneath you.
## Offset pagination
Some existing endpoints page by offset instead: you ask for a `limit` and skip a number of records with `offset`.
| Parameter | Description | Default |
| - | - | - |
| `limit` | Number of records to return | Varies by endpoint |
| `offset` | Number of records to skip from the start of the result set | `0` |
Offset responses include a `count` — the total number of records matching your query — so you can calculate how many pages there are. To walk the full set, increase `offset` by `limit` on each request until `offset` reaches `count`:
```bash theme={null}
# First page
curl "https://api.spirii.com/v2/tokens?limit=500&offset=0" \
-H "Authorization: Bearer "
# Second page
curl "https://api.spirii.com/v2/tokens?limit=500&offset=500" \
-H "Authorization: Bearer "
```
## Which pagination an endpoint uses
Check the endpoint's parameters in the [API reference](/api-reference/overview): a `nextPageCursor` parameter means cursor-based, an `offset` parameter means offset-based. Two differences catch people out when moving between endpoints:
* **Default and maximum page size vary.** A cursor endpoint might default to 25 records (max 100), while an offset endpoint defaults to 500 (max 1000). Set `limit` explicitly rather than relying on the default.
* **Only offset responses return a total.** If you need a count, read it from `count` on an offset endpoint; cursor endpoints don't provide one.
If your integration reads from several endpoints, handle both styles: branch on whether the response returns a `nextPageCursor` or a `count`, rather than assuming one scheme everywhere.
## Related
Narrow and sort list results with query parameters.
The exact pagination parameters each endpoint accepts.
# Price pylon
Source: https://docs.spirii.com/developers/pylon
Show a site's current charging price and how many chargers are free, to drive a price pylon.
A pylon is the physical sign at a site that shows the current charging price and how many spots are free — familiar from fuel stations, and increasingly common at charging sites. By the end of this playbook you'll be able to read both figures from the API and keep them current on the display.
## Before you start
You'll need an [API key](/developers/authentication), and the ID of the [location](/components/charging/locations) the pylon serves. Both figures come from that location: its EVSEs carry their status, and their connectors carry the tariff that sets the price.
## Show the current price
Fetch the site by ID. Each EVSE's connectors carry `tariffIds` — the currently valid tariffs for that connector.
```bash theme={null}
curl https://api.spirii.com/v2/locations/12345 \
-H "Authorization: Bearer "
```
```json theme={null}
"evses": [
{
"status": "AVAILABLE",
"connectors": [
{ "id": 1, "tariffIds": ["58652fe8-d840-4aa4-bb4f-3ebd944df9d6"] }
]
}
]
```
Fetch the tariff by that ID:
```bash theme={null}
curl https://api.spirii.com/v2/tariffs/58652fe8-d840-4aa4-bb4f-3ebd944df9d6 \
-H "Authorization: Bearer "
```
The price per kWh is the `price` on the price component of type `ENERGY`; the `currency` sits on the tariff. The `price` is exclusive of VAT — apply the component's `vat` if the pylon shows a consumer-facing, VAT-inclusive figure.
A tariff can hold more than one element, each with its own `restrictions` (time of day, day of week, date range). Elements are evaluated top to bottom, and the first whose restrictions match applies — so to show the *current* price, pick the first element whose restrictions are satisfied right now, then read its `ENERGY` component. A tariff with a single, unrestricted element has one price. The structure follows OCPI 2.1.1.
## Show charger availability
Fetch the same location and count the EVSEs whose `status` is `AVAILABLE` — that's the number of free charging spots.
```bash theme={null}
curl https://api.spirii.com/v2/locations/12345 \
-H "Authorization: Bearer "
```
The `status` on each EVSE is an OCPI value — `AVAILABLE`, `CHARGING`, `BLOCKED`, `OUTOFORDER`, and so on — so a simple count of `AVAILABLE` EVSEs gives the free-spot figure for the display.
## Keep it current
A single location call returns both the EVSE statuses and the connector `tariffIds`, so one request per refresh covers availability. Tariffs change rarely — fetch each one once and cache it, refetching only when a connector's `tariffIds` change.
* **Poll on a sensible interval** and stay within the [rate limit](/developers/rate-limits) of 120 requests per minute — availability changes far faster than price, so you can refresh it more often.
* **Evaluate tariff restrictions in local time**, so time-of-day pricing flips at the right moment on the display.
* **Fail gracefully.** If a request errors, keep showing the last known values rather than blanking the pylon, and retry with backoff. See [Errors](/developers/errors).
## Related
The site, its EVSEs, and their connectors and status.
EVSE status values and what they mean.
# Quickstart
Source: https://docs.spirii.com/developers/quickstart
Make your first authenticated request against the Spirii Public API.
This quickstart walks you through making your first authenticated request.
Create an API key via Spirii Connect. Navigate to [API tokens](https://connect.spirii.com/team?activeTab=api_tokens\&limit=24\&page=1) under Team Access. Upon creation, you will receive your unique API key via a secure one-time link.
This link can only be opened once, so ensure you store your key securely after accessing it.
Replace `YOUR_API_KEY` and run:
```bash curl theme={null}
curl https://api.spirii.com/v1/locations \
-H "Authorization: Bearer YOUR_API_KEY"
```
```javascript Node.js theme={null}
const res = await fetch("https://api.spirii.com/v1/locations", {
headers: { Authorization: `Bearer ${process.env.SPIRII_API_KEY}` },
});
console.log(await res.json());
```
```python Python theme={null}
import os, requests
r = requests.get(
"https://api.spirii.com/v1/locations",
headers={"Authorization": f"Bearer {os.environ['SPIRII_API_KEY']}"},
)
print(r.json())
```
Every endpoint has a try-it playground. See [API Reference](/api-reference/overview).
Only Spirii Connect users with an **Operator** role or higher can create API tokens.
# Rate limits
Source: https://docs.spirii.com/developers/rate-limits
Learn about the API rate limits and how to work with them.
The Spirii API endpoints are safeguarded against bursts of incoming traffic to help maximise their stability.
## Rate limitation
For all endpoints available in the Spirii API, the following rate limits apply:
**Rate limit:** `120` per minute.
## Data limitation
Specifically for the **GET CDRs** endpoint, a limitation of `5000` records per request applies.
# Reporting and dashboards
Source: https://docs.spirii.com/developers/reporting-and-dashboards
Pull Spirii platform data into your own dashboards, business reports, and financial exports.
By the end of this playbook you'll know which Spirii data to pull, and how to pull it reliably, to power reporting your own way — a live operations cockpit, an automated month-end report, or a tailored financial export.
## Before you start
This playbook is for operators and e-mobility providers who need reporting beyond what Spirii Connect offers out of the box. Connect already gives you a business overview, live operational dashboards, and CDR exports; reach for the API when you need custom KPIs, your own storage, or feeds into other systems.
You'll need an [API key](/developers/authentication) and a working understanding of [sessions and CDRs](/components/charging/sessions-and-cdrs), which are the backbone of most reports.
## What you can build
* A **live operations cockpit** showing connector availability and faults across your network.
* An **automated business report** — daily or monthly usage, revenue, and utilisation, sent to your operations or management team.
* A **financial export** for your accounting system. Invoicing and reconciling from CDRs is covered in the [ERP integration](/developers/erp-integration) playbook.
* A **performance dashboard** to spot utilisation trends and margin opportunities.
## The data you'll use
Four resources cover almost every reporting need. Follow the component link for what each represents; use the reference for the full schema and every field.
| Resource | Why it matters for reporting | Read more |
| - | - | - |
| Charge detail records (CDRs) | Completed, billable sessions — the spine of most reports | [Component](/components/charging/sessions-and-cdrs) · [Reference](https://docs.spirii.com/api-reference/charge-records-v2/get-a-list-of-cdrs) |
| Transactions | Sessions in progress or recently finished, for near real-time views | [Component](/components/charging/sessions-and-cdrs) · [Reference](https://docs.spirii.com/api-reference/transactions-v2/get-a-list-of-transactions) |
| Locations | Site metadata and live EVSE and connector status, for mapping and fault detection | [Component](/components/charging/locations) · [Reference](https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations) |
| Tariffs | The price structure behind a session, to correlate revenue with pricing | [Component](/components/commercial/tariffs) · [Reference](https://docs.spirii.com/api-reference/tariffs-v2/fetches-a-single-existing-tariff) |
### What a CDR gives you
A single CDR carries most of what a report needs, so you rarely have to stitch resources together:
* **Energy and time** — `consumed` (kWh), `duration` (charging, idle, total), `startedAt` / `endedAt`, `highestPowerDrawn`.
* **Money** — `price` (amount, `amountExVat`, `currency`, `vatRate`), and `cpoDefaultPrice` (the price before vouchers and discounts, useful for margin analysis).
* **Pricing** — `price.tariffId` and `tariffName` are embedded, so you can attribute revenue to a tariff without a second call.
* **Who and how** — `auth` (method and charge key), `paymentMethod`, `paymentStatus`, and `voucher` where one applied.
* **Where** — `location` (name, city, country, type), `evseId`, `chargeBoxId`.
* **Roaming** — `isRoaming` and `roamingDetails` to separate roaming sessions from your own network.
Some charge key and customer fields are personal data and are only returned with sufficient access. Use the `fields` parameter to request only the properties your report needs and keep payloads small.
## Integration patterns
### Live operations cockpit
1. Poll [Locations](https://docs.spirii.com/api-reference/locations-v2/fetches-a-list-of-locations) on a short interval for current EVSE and connector status, scoping the request to the sites you care about.
2. Poll [Transactions](https://docs.spirii.com/api-reference/transactions-v2/get-a-list-of-transactions) for sessions in progress, using its `updatedAt` filter to fetch only what changed since your last pull.
3. Surface current availability and faults, and flag anything stuck.
### Nightly report
1. Query CDRs for the day's completed sessions with the `updatedAtFrom` and `updatedAtTo` window:
```bash theme={null}
curl "https://api.spirii.com/v2/charge-records?updatedAtFrom=2025-01-27T00:00:00.000Z&updatedAtTo=2025-01-28T00:00:00.000Z&limit=5000" \
-H "Authorization: Bearer "
```
2. Store the records locally, then compile and send the day's usage and revenue summary.
### Monthly report
1. Aggregate the CDRs you've stored over the month rather than refetching them.
2. Group by location, tariff, or payment method to build the figures management needs — most of what you need is already on each CDR.
3. For advanced slicing, the CDR endpoint accepts a `filter` parameter (a JSON query) so you can, for example, return only the sessions at a set of locations:
```text theme={null}
/v2/charge-records?filter={"location.id":{"$in":[12345,67890]}}
```
Two limits shape any reporting integration: requests are capped at **120 per minute**, and a CDR request returns at most **5,000 records**. Page through larger result sets, and see [Rate limits](/developers/rate-limits).
## Best practices
* **Sync incrementally.** Pull only what changed using each endpoint's time filter rather than refetching everything. The parameter names differ by endpoint — CDRs use `updatedAtFrom` / `updatedAtTo`, transactions use `updatedAt` — so confirm each on the reference. See [Filtering](/developers/filtering).
* **Page through completely.** List endpoints return results in pages; follow the cursor to the end, and set `limit` explicitly rather than relying on defaults. See [Pagination](/developers/pagination).
* **Store CDRs locally.** Keep a copy of completed records to cut repeat calls and stay clear of the rate limit.
* **Retry safely.** Back off and retry on transient errors; don't retry a rejected request unchanged. See [Errors](/developers/errors).
* **Map identifiers across systems.** Align on `location.id` and `evseId` when joining Spirii data with your own, to keep records consistent and catch duplicates. See [Identifiers](/developers/identifiers).
## Next steps
Give a fleet operator visibility and control over their drivers' charging.
Set up the price pylon integration.
# Versioning
Source: https://docs.spirii.com/developers/versioning
The Spirii API follows Semantic Versioning, ensuring a clear and predictable versioning structure
## Version in the URL
Every Spirii REST API is versioned in the URL path, and each API is versioned independently — a major bump on one does not move the others.
| API | Current version | Example |
| - | - | - |
| Spirii API | **v2** | `https://api.spirii.com/v2/locations` |
| eMSP API | **v1** | `https://api.spirii.com/emsp/v1/locations` |
| Billing API | **v1** | `https://api.spirii.com/reimbursement/v1/expense-reports` |
| Energy Management API | **v1** | `control-request` channel |
Where the version sits differs by API. The Spirii API puts it first, directly after the host. The eMSP and Billing APIs put it after their path prefix (`/emsp/`, `/reimbursement/`). Read the version from the endpoint's own path rather than assuming a position.
The Energy Management API is the exception. It is asynchronous, and its channel addresses are provisioned per actor during onboarding, so there is no path for you to read a version from. Its version is declared in the [AsyncAPI document](/capabilities/smart-charging/overview) instead.
## What counts as a breaking change
The following changes are considered breaking and trigger a major version bump:
* Removing or renaming a field on a response object.
* Removing an endpoint or HTTP method.
* Changing the type of an existing field.
* Tightening validation on request bodies in a way that rejects previously valid input.
The following are **not** breaking and may ship in any minor version:
* Adding new endpoints.
* Adding new optional request parameters.
* Adding new fields to response objects.
* Adding new enum values to existing fields.
When parsing responses, treat unknown fields as ignorable and unknown enum values as a generic fallback. This keeps your integration forward-compatible with minor releases.
# Your first login
Source: https://docs.spirii.com/get-started/first-login
From the invitation email to a working Spirii Connect account.
Your administrator has invited you to Spirii Connect, and this guide takes you from that invitation email to a working, secured account: logged in, protected with multi-factor authentication, and set up the way you want it.
## Before you start
* Your account is created for you, by an administrator at your organisation or by Spirii. You don't sign up yourself.
* You'll receive an **email invitation** at the address you were registered with.
* Have a smartphone with an **authenticator app** ready for multi-factor authentication (Microsoft Authenticator, Google Authenticator, or similar).
## Steps
You'll get an email from **[noreply@mail.spirii.com](mailto:noreply@mail.spirii.com)** with the subject **Welcome to Connect**. Open it and click **Accept invite**. Do this within two days, since the invitation expires after that and you'll need a new one.
Accepting the invite takes you to a secure page. Choose a password, confirm it, and submit. You'll see a message confirming your account is set up, and you can close the page.
Go to [connect.spirii.com](https://connect.spirii.com), worth bookmarking, and sign in with your email and the password you just created.
MFA is required. On screen you'll see a QR code; open your authenticator app, scan it, and enter the six-digit code to confirm. You can also choose to **trust this device** so you won't be asked for a code every time you sign in from it, which is handy on your own work machine.
You're in when the invitation email leads you all the way to the Connect dashboard, with MFA active on your account. From here, what you can see and do depends on the role you were given.
## Set up your profile
Your **Profile** holds a couple of personal settings, reached from your name in the bottom-left of Connect.
Open Profile, choose your language (German, for example), and save. The platform switches straight away. This applies to your account only and doesn't change anything for your colleagues, and you can change it again whenever you like.
Connect is available in English, German, French, Italian, Spanish, Portuguese, and Danish.
Turn this on to preview and try upcoming platform features before they're released to everyone. It's a good way to get an early look, with the understanding that beta features are still being refined.
## Next steps
Get your first charger online and ready to charge.
Bring colleagues and customers into Connect, and set what each of them can do.
Set up a depot and get your drivers charging, on site and on the road.
# What is Spirii?
Source: https://docs.spirii.com/get-started/what-is-spirii
One EV charging platform for CPOs and eMSPs.
Spirii is an end-to-end EV charging platform that serves both sides of every charge: the operators who run the chargers, and the businesses that connect drivers to them. Our vision is to become the trusted platform that powers simpler, smarter charging experiences.
Spirii sits in the middle of the charging value chain, connecting charging networks with drivers and fleets. Across one platform, Spirii handles the infrastructure layer, simplifies operations, secures interoperability, and manages the financials.
Whether you are operating a public charging hub, electrifying a fleet, or building your own charging experiences, you interact with the same platform.
## One charging platform for CPOs and eMSPs
Bringing chargers online, setting pricing and access, monitoring uptime, and earning the revenue from the energy you sell.
Giving drivers a way to find, start, and pay for a charge — through an app, a charge key, or roaming onto other networks.
Most players aren't one or the other.
* A CPO that issues charge keys to its own drivers is also acting as an eMSP.
* A fleet that operates depot chargers and handles on-the-route charging is both.
Spirii doesn't ask you to choose; use the capabilities that fit your business.
## Next
The roles and the core objects every capability is built on.
Bring your first chargers online and start charging.
# Quick start for CPOs
Source: https://docs.spirii.com/guides/cpo-quickstart
Get your first charger online and ready to charge with Spirii.
By the end of this guide, you'll have your first charger online on the Spirii platform and ready to charge. You'll set up the customer, location, and charge box end to end.
## Before you start
This guide is for operators with charging hardware ready to install, or migrating from another platform. You'll need operator access in Spirii Connect, and your installer should know how to point the charger's connection to Spirii.
## Steps
The customer is the organisation that owns the location: your own organisation, or one of your clients.
See [Customer management](/capabilities/account/customer-management) for the customer hierarchy and what ownership decides.
Set up the site where the charger will be installed: its name, address, and accessibility settings. Keep the location **private** for now, so drivers can't reach it before it's ready. You'll publish it once the charger is online.
[Location configuration](/capabilities/connection/location-configuration) goes through the site's details, publishing settings, and opening hours.
On the location, open the **Charge boxes** tab and add a charge box. Set the connection method (typically OCPP) and the charge box ID (CBID), the charger's unique identifier.
This creates a placeholder on the location, pending the charger's first connection. The charge box shows as **pending**.
The API route to this step, and the settings a charge box carries, are in [Charger activation](/capabilities/connection/charger-activation).
Once the charger is installed, point its connection URL to Spirii at `wss://ocpp.spirii.com`. On the first `BootNotification` the charger sends (its initial OCPP handshake), the platform automatically unpacks and populates the charger's settings, model information, EVSEs, and connectors.
The charge box now comes online.
[Charger activation](/capabilities/connection/charger-activation) also describes what the platform reads back here, and how to import a configuration from an identical unit.
Because the location is still private, create a voucher code to grant yourself access, then start a charge to confirm everything works.
Beyond testing, [Voucher access](/capabilities/access/voucher-access) explains how voucher groups open selected locations to a chosen group of drivers at a price you set.
## Verify
While charging, the session appears in the **Ongoing sessions** tab on the location. When it ends, a charge detail record (CDR) is generated for the session.
## Troubleshooting
* **The charger won't come online.** No `BootNotification` is reaching the platform: confirm the connection URL points to `wss://ocpp.spirii.com` and that the installer configured the charger correctly.
* **The charger connects but the charge box stays pending.** Check that the CBID you entered matches the charger's actual identifier; a mismatch leaves the placeholder unlinked.
## Next steps
Add a tariff (and an optional roaming tariff), then set the location to public and enable roaming to let external drivers charge.
Use voucher groups to grant access or special pricing to chosen users, attachable to app users or RFID charge keys.
# Quick start for fleets
Source: https://docs.spirii.com/guides/fleet-quickstart
Get your fleet charging at your own depot, and out on the road across other networks.
This guide takes a fleet from nothing to charging in two parts.
A site your own drivers charge at, closed to everyone else.
Those same drivers charging across other networks, on the same charge keys.
Each step keeps to the shortest path and links to the capability that covers it in depth.
## Before you start
You'll need:
* A Spirii Connect account with CPO access.
* A charger installed on site and ready to connect.
* Your fleet's RFID keys, or the VIN or MAC address of each vehicle for Autocharge.
Throughout, the examples follow Acme Inc., a fleet running a depot at Munich DC Hub.
## Part 1: Set up your depot
The goal: a private depot where your fleet charges for free, closed to everyone else.
Every location bills against a tariff, so create one first. For charging your own fleet, make it 0 EUR. Paid pricing can come later if you open the site to others. See [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic) for how tariffs are built.
Create Munich DC Hub under your Acme Inc. customer account, enter its address, and link the tariff. Leave it unpublished: a private depot isn't listed in any app. [Location configuration](/capabilities/connection/location-configuration) covers the full set of options.
Add your charger to the location and bring it online. You'll see it move from Pending to Online once it connects. [Charger activation](/capabilities/connection/charger-activation) walks the connection, and the [Quick start for CPOs](/guides/cpo-quickstart) has the detailed first-charger flow if you want it.
Create your drivers' charge keys, billed to Acme Inc., then put them in a charge key group and bind that group to Munich DC Hub. Because the site is private, only charge keys in the group can charge there, which makes the depot exclusively your fleet's. [Charge key authentication](/capabilities/access/charge-key-authentication) covers issuing charge keys and bulk-loading a whole fleet at once.
You'll know Part 1 worked when a driver taps their key at the depot and charging starts. The session then appears in Connect, billed to Acme Inc. at 0 EUR.
## Part 2: Put your drivers on the road
The goal: the same drivers charging away from the depot, on other operators' networks.
Turn on roaming for the [charge keys](/capabilities/access/charge-key-authentication) you issued, and check each is active and labelled in the `DK.SPI.C{customerPrefix}` format. A correctly labelled, roaming-enabled charge key is what lets a driver charge outside your own network.
Your drivers charge on other networks through your branded app or Spirii Go. Each driver installs the app, adds their key, and either sets up payment or relies on the Acme Inc. billing you configured. See [Roaming connection](/capabilities/roaming/roaming-connection) for how roaming access works.
Use the Charge map in Connect to see every charger your drivers can reach (your own, public, and roaming), and filter a route for the right connector and vehicle type. See [Network coverage](/capabilities/roaming/network-coverage).
You'll know Part 2 worked when a driver charges at another operator's charger and the session lands back in Connect as a roaming session, billed to Acme Inc.
## Next steps
Make the site public and set opening hours to earn revenue outside your fleet's charging times. Covered in [Location configuration](/capabilities/connection/location-configuration) and [Location access](/capabilities/access/location-access).
Distribute charging across the site so a full depot doesn't overload the supply.
Set paid and roaming tariffs once you open the site beyond your own fleet.
The single-charger walkthrough, if you want the depot's charger flow in full.
# Home & work
Source: https://docs.spirii.com/guides/home-and-work
Charging at home, at the office, and on public networks — attributed to the right payer and reimbursed on one charge key.
Electrifying company cars moves refuelling from the filling station to the employee's driveway, which turns a fuel card into something you have to measure, attribute, and pay back.
## Overview
Home and work charging succeeds on three things.
One charge key at home, at work, and on the road.
Home charging measured accurately and paid back without manual claims.
Workplace power shared fairly between company cars, employees' own cars, and guests.
The four phases below take the setup from configuration to the monthly cycle:
Set up the workplace, the home chargers, and the way employees are onboarded.
Confirm a home session reaches an expense report and a workplace session bills the right group.
Run the employee lifecycle, and keep the workplace within its supply.
Reimburse home charging, and account for what the company pays elsewhere.
The last two repeat every month. A final section covers the same drivers charging on the road.
## Before you start
This guide is for the organisation that employs the drivers: the employer running chargers at its own sites, and the fleet or mobility manager responsible for company cars. Both sides sit in one Spirii account, which is what lets a single charge key work at the office, at an employee's house, and on a public charger.
Tax treatment of home charging as a benefit differs by market and belongs with your finance and legal advisers. The configuration steps for reimbursement have their own guide, [Home charging reimbursement setup](/guides/home-charging-reimbursement-setup); this page covers where they sit in the wider sequence.
## Configure
### Upfront decisions
| Decision | Consequence | Documented in |
| - | - | - |
| Who is billed at each site | A company car charging at home is reimbursed to the employee. The same car at the office is a cost the company carries. An employee's own car at the office may be something they pay for. Each needs its own tariff and access route. | [Location access](/capabilities/access/location-access) |
| How employees are onboarded | An onboarding flow creates the customer, the residential location, the app account, and the installation request from one order the employee places. Setting these up by hand stops scaling somewhere around the first hundred employees. | [Onboarding flows](/capabilities/automation/onboarding-flows) |
| Which app your drivers use | Spirii Go works today with nothing to build. A branded app puts the sign-up, the terms, and the driver relationship under your own name, and takes a build and a store release to reach. | [Spirii Go and branded apps](/capabilities/driver-experience/spirii-go-and-branded-apps) |
| How reimbursement is paid | Through your own payroll, so every payment to an employee sits in one place, or through Spirii's licensed payment provider, which disburses to each employee's bank account once you transfer the total. | [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) |
### The workplace
A workplace car park serves several groups at once, and separating them is the whole design problem.
| Who charges | How they get access | What they pay |
| - | - | - |
| Company car drivers | Their issued charge key, in a charge key group bound to the site | Nothing, on a free tariff billed to the company |
| Employees' own cars | Their own app account, or a voucher you issue | A rate you set, paid by them or subsidised through a voucher |
| Guests and visitors | The site published during office hours, or a voucher for expected visitors | The public tariff, or the voucher rate |
A [voucher](/capabilities/access/voucher-access) is what makes this work on one set of chargers. It carries its own price and its own audience, so employees charge at a reduced rate on the same units where guests pay full price.
Where the site has both AC and DC chargers that should carry different prices, run them as separate locations at the same address. A location holds one tariff, so mixing the two leaves you unable to price them apart.
Publishing the site outside office hours is worth considering: the car park is full when your employees are in the building and empty when they aren't. [Location configuration](/capabilities/connection/location-configuration) covers opening hours and publishing.
### The employee's home
An [onboarding flow](/capabilities/automation/onboarding-flows) takes an employee from a benefit entitlement to a working charger. They place one order through your branded flow, and everything their setup needs is created and connected behind it, including an installation request routed to the installer covering their postcode.
The records it creates matter, because reimbursement depends on their shape. The employee becomes a customer in their own right, sitting beneath your fleet account, and the residential location at their address belongs to that employee record.
Three conditions then make a home session reimbursable.
Set in Spirii Connect, it links the location to your fleet account.
Through that child customer record. Setting your own company as the owner because it bought the hardware is the common mistake, and it stops sessions being attributed.
Either the charger requires authentication, so each session carries the employee's charge key, or the location has *Reimburse all sessions to the location owner* turned on, so every session recorded there is reimbursed to the employee. Use the setting only where the employee is the one person charging at that address.
Unless the location reimburses all sessions, a home charger left in free-vend mode still charges the car, but its sessions carry no charge key and cannot be attributed to an employee. They never reach the expense report, so nobody is paid back for them. Check authentication is enabled, or the setting is on, before an employee starts using the charger.
The rate each employee is reimbursed at sits on their home location, on its **Rates** tab in Connect. See [Reimbursement rates](/capabilities/billing-payouts/home-charging-reimbursement#reimbursement-rates).
Issue each employee a charge key billed to your fleet account, so the same key works at the office and on public chargers. See [Charge key authentication](/capabilities/access/charge-key-authentication).
Employees can also control a home charger from the app, scheduling charging for the cheapest hours ahead. That works on charge box models Spirii has validated for it, so confirm the hardware you offer supports it before promising it as part of the benefit.
## Validate
Run one employee end to end before the rollout, covering all three places they charge.
A session on `CAR-07` at the office should produce a charge detail record billed to `Acme Inc.` at the company car tariff, not the visitor rate.
A session on the employee's home charger should appear against that employee, with an estimated cost attached. If it doesn't, check the Company Car agreement, the location owner, and authentication or the location's reimburse-all-sessions setting, in that order.
The home session should appear inside that employee's total on the monthly Fleet Expense Report, under **Reimbursements** in Connect, before you approve anything.
A session on another operator's charger should land back in Connect against the same charge key, billed to `Acme Inc.`
The setup is ready to roll out when you have:
* A workplace session billed to the company at the right tariff
* A home session attributed to the employee with a reimbursement amount
* That session visible in a Fleet Expense Report
* A public session billed to the company on the same charge key
## Operate
The workload here is people, not hardware. Employees join, change cars, move house, and leave, and each of those is a change in three places at once.
### The employee lifecycle
The onboarding flow does most of it. What remains is issuing the charge key, adding it to the workplace charge key group, attaching the Company Car agreement to their home location, and setting their reimbursement rate on it.
Disable the charge key instead of deleting it: a disabled charge key stops charging immediately and keeps the history it appears in, while a deleted charge key's identifier can never be reused. Then close out the final month's reimbursement. What happens to the charger at their address is a commercial question, not a platform one.
The residential location is tied to an address, so a new address means a new location, a new Company Car agreement and reimbursement rate, and installation at the new property.
### Power at the workplace
Most employees arrive within the same hour, so a car park's demand peaks between 08:00 and 09:00 and stays flat for the rest of the day. [Load balancing](/capabilities/energy-management) distributes what the circuit allows across whatever is plugged in, so the site absorbs that peak without tripping a fuse or needing a bigger connection.
Where the car park sits idle overnight and at weekends, its chargers are a candidate for [grid balancing](/capabilities/energy-management/grid-balancing), which earns from brief adjustments to charging power when the grid needs them. It runs in Denmark today, and that page carries the hardware and portfolio requirements.
### Monitoring
Home chargers are the part you hear about last, because an employee whose charger has failed calls their fleet manager. [Alerts and the monitoring list](/capabilities/operation-monitoring/faults-and-alerts) cover the home chargers in your account alongside the workplace ones, so a fault reaches you first.
## Settle
Money runs through this setup in three directions.
Each month the platform aggregates every employee's home sessions into a Fleet Expense Report, which you review, adjust, and approve under **Reimbursements** in Connect. Payment then follows the route you chose, and the employee receives their own report without submitting a claim. See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) for the cycle in full.
Sessions on your own workplace chargers are internal, so attribution is what matters there. Sessions on other networks arrive as one consolidated invoice covering everything your drivers used. See [Charge key billing](/capabilities/billing-payouts/charge-key-billing).
Charging by employees' own cars and by visitors is collected by Spirii and paid out monthly, as at any public location. See [Understanding your payout](/capabilities/billing-payouts/payouts).
Because every session carries its charge key and customer, an [export](/capabilities/reporting-analytics/exports) splits the whole picture by employee, by site, or by cost centre, which is what a finance team needs to see the real cost per car.
## On the road
Company car drivers charge away from home and the office, and the same charge key covers it.
Enable roaming on each charge key, keep it active, and label it in the format [Roaming connection](/capabilities/roaming/roaming-connection) describes, so it authorises across the networks Spirii connects to. Drivers find those chargers in Spirii Go or your branded app, alongside your own workplace sites. See [Network coverage](/capabilities/roaming/network-coverage).
Those sessions bill to the company automatically, which is what turns the charge key into a fuel-card replacement.
## Continuous optimisation
The fleet changes shape as it electrifies. Early adopters are followed by employees who didn't take a company car first time round, so workplace demand keeps climbing after the reimbursement setup has settled. Revisit the car park's capacity before the queue forms.
The monthly rhythm is the [expense report](/capabilities/billing-payouts/home-charging-reimbursement#getting-the-report). Approving it is also the moment to read it: which employees charge almost entirely at home, which rely on public charging that costs several times as much, and where a workplace charger or a home installation would pay for itself.
## Next steps
The configuration steps for operators, employees, and chargers.
The shortest path to a site and drivers on the road.
Differentiated access and pricing for employees, visitors, and guests.
How workplace and public charging reaches the company's invoice.
# Set up home charging reimbursement
Source: https://docs.spirii.com/guides/home-charging-reimbursement-setup
Configure operators, fleet customers, and employees for automated home charging reimbursement.
Get a fleet's employees charging their company cars at home and being reimbursed automatically each month, from operator configuration through to the first expense report.
## Before you start
* The CPO operator is set up in Spirii Connect and the Business Portal
* You have the employee list and their home charger hardware
* Where Spirii disburses the money, the fleet company has completed KYC with Paytech, Spirii's PSP partner, and you have each employee's IBAN
Employees can start charging at home before PSP onboarding finishes — only the disbursement waits: expense reports still generate, but no money moves until the KYC is complete. Where the fleet reimburses through its own payroll instead, none of the PSP requirements apply.
## Steps
The fleet company is created as a customer. Where Spirii disburses the money, this data has to be accurate for the PSP integration.
| Field | Notes |
| - | - |
| Business name | Must match exactly what was submitted on the KYC documents to Paytech |
| Full address | Street, city, postal code, country |
| Invoice email | Fleet Expense Reports are sent here |
Changing any of it after PSP onboarding needs a manual update by Spirii, so get it right the first time. Where the fleet reimburses through payroll, only the invoice email really matters.
Each employee is created as a customer in Connect.
| Field | Needed for |
| - | - |
| First and last name | PSP sanctions screening |
| IBAN | PSP disbursement |
| Email | Their individual expense report |
The first two are only required where Spirii disburses. Employees can come in through Spirii's onboarding flows, or be created by hand.
Each employee's home charger is registered as a location, with these set:
1. **A Company Car agreement.** A financial agreement with its type set to Company car, linked to the fleet customer. It holds the company car management fee, whether tax is excluded from the reimbursement, and a fallback reimbursement rate.
2. **A reimbursement rate on the location.** On the location's **Rates** tab, set the price per kWh the employee is paid, its start date, and the currency, and attach the evidence behind it, such as their electricity bill. A rate on the location takes precedence over the rate on the agreement.
3. **The location owner set to the employee.** Not the fleet company, and not the CPO. Setting the company as owner because it bought the hardware is the common mistake, and it stops sessions being attributed.
4. **How sessions are attributed.** Either the employee starts every session with their charge key, or the charger at least sends OCPP authorisation messages to the platform. Or turn on *Reimburse all sessions to the location owner* in the location's Reimbursement section, and every session recorded at the location is reimbursed to the employee, whether a charge key was used or not. Use the setting only where the employee is the one person charging there, since it reimburses everyone's sessions to them.
Without that setting, a charger left in free-vend mode cannot attribute sessions to an employee, and those sessions never reach an expense report.
Each employee needs a charge key, an RFID card or a virtual one in the app, linked to their customer account. It has to be **active** before any session can be attributed to them. Where the location reimburses all sessions, home sessions don't depend on it, but the employee still needs it everywhere else.
## Verify
Ask the employee to run a test session at their home charger, then check it landed.
The session appears in Connect under the employee's location, and its CDR shows the employee's charge key as the authentication (unless the location reimburses all sessions), their location, the fleet company as the billing customer, and the reimbursement rate applied. An expense report is created for the fleet, or an expense is added to the report already open.
If the CDR is missing or the billing customer is wrong, check the Company Car agreement, the location owner, and the charge key linkage before going further.
Once the first billing cycle closes, the fleet manager receives a Fleet Expense Report by email, and can also download it in Connect as a PDF or CSV or pull it over the API. Review it to confirm every employee who charged appears, that session counts and kWh match Connect, and that the amounts match the rate on the location, or the agreement rate where the location has none.
## Correcting missing sessions
If a session does not appear in an employee's expense report:
1. Check the charger location has the Company Car agreement set correctly
2. Check the session's authentication matches the employee's charge key, or that the location reimburses all sessions
3. If both are right and the session is still missing, the fleet manager can add it to the expense report by hand in Connect
If an employee has no expense report at all, because no session was ever attributed to them, a report cannot be created after the fact. They need at least one correctly attributed session for the first one to generate.
## Next steps
How the reimbursement works end to end, including the Company Car agreement.
The wider setup for company cars across home, workplace, and public charging.
How to issue and manage employee charge keys.
Automating employee, location, and charger creation from a single order.
# Migrate to Spirii
Source: https://docs.spirii.com/guides/migrate-to-spirii
Planning, testing, and running a charger and charge key migration without disrupting the drivers using your network.
You migrate a charging network to Spirii by repointing each charger's Open Charge Point Protocol (OCPP) connection to Spirii's backend, once the locations and charge boxes exist in Spirii Connect ready to receive them.
## Before you start
This guide is for a charge point operator moving an existing network from another charge point management system (CPMS) onto Spirii. It covers chargers and charge keys. Your commercial exit from your current provider, and the physical installation itself, sit outside it.
Know these three things before you plan a date.
Repointing a charger's OCPP endpoint moves it to Spirii and ends its connection to your current platform. There is no dual-run period, so each charger has a single cut-over moment.
A charge box arrives in Spirii fresh, with no past sessions or charge detail records behind it. Request an export of your historical data from your current provider before your contract with them ends.
Chargers published to roaming networks need the coordination described below. Chargers that aren't published migrate with no partner-facing impact.
### Remote or on-site
A remote migration is the cheaper approach, and it needs every charger in scope reachable through its manufacturer's backend or over a VPN via its installed SIM. Older units without that access need a technician at the charger to change the setting by hand, which is slower and has to be scheduled around site access.
Most networks end up with a mix: remote for the recent hardware, on-site for the rest. Split your inventory that way early, so the on-site work runs in parallel with the batches that can move remotely.
Three other things extend a migration beyond the remote path, so establish early whether they apply: a SIM card swap or router setup, replacing the EVSE ID labels on your chargers, and new graphics for charger screens.
## How a migration runs
Four phases. For a network of fifty chargers or more migrating remotely, the whole sequence typically runs about three months.
| Phase | What happens | Typical duration |
| - | - | - |
| Pre-migration | Agree the approach, collect the data, and build the network in Connect | 2–3 weeks |
| Migration test | Move a small batch and confirm every part of the chain works | 1–2 weeks |
| Migration | Move the rest, in batches | 1–4 weeks |
| Post-migration | Verify against live traffic until two billing runs check out | 4–8 weeks |
Spirii can run the migration alongside you, coordinating with your current provider so operations stay live throughout. Talk to your Spirii representative about which parts you want to own.
## 1. Pre-migration
### Collect the data
Every charger you migrate needs a row of data before it can be created in Connect.
| Group | What to collect |
| - | - |
| Site | Name, street and number, postcode, city, country, latitude and longitude, location type, and how the site is used |
| Charge point | Manufacturer, model, serial number, firmware version, maximum power in kW, connector types, and the physical order of connectors left to right |
| Identification | The EVSE ID in eMI3 format (country code, operator ID, and EVSE number), and the charge point number printed on the unit |
| Screens | Screen size, for units that have one |
| Connectivity | SIM operator and ICCID, and how the charger is reached for configuration |
| Commercial | The tariffs each site bills against, the charge keys and users to bring across, and the site manager and installation partner for each location |
The physical connector order matters more than it looks. It's what makes connector `DE*SPI*E00012345*1` in the platform the same socket a driver is standing in front of.
Record the model and firmware version for every unit, and confirm each one against the models and firmware levels Spirii has validated. This is the prerequisite the rest of the plan rests on: a model that turns out not to be validated needs corrective action from its manufacturer and a repeat test afterwards, which moves every date behind it. Your Spirii representative confirms the current levels, and [Charger validation](/capabilities/connection/charger-validation) explains what's tested and where to check a model.
Agree how configuration access is granted, and keep charger credentials out of any shared file. Access is usually given through your manufacturer backend to the people doing the work.
### Build the network in Connect
Create the customers, locations, and charge boxes before migration day. Each charge box waits as a placeholder until its physical charger reaches it, and takes no sessions until then, so building them ahead of a batch has no effect on traffic still running on your current platform. See [Charger activation](/capabilities/connection/charger-activation).
There are two routes:
Create each location and charge box by hand. This suits a small network, and it's how you make a correction after a bulk run.
Build the whole network in one pass from the data you collected: [`POST /locations`](/api-reference/locations-v2/creates-a-new-location) and [`POST /chargeboxes`](/api-reference/chargeboxes-v2/creates-a-new-charge-box).
Spirii can also run the creation for you from your collected data. And if you're integrating the Spirii API into your own systems as part of the move, that work runs in parallel with the migration rather than waiting for it to finish.
Alongside the infrastructure, set up what makes the sites operational:
* **[Tariffs](/capabilities/pricing/pricing-options-and-logic)** — the price each location's chargers bill against
* **Publishing and roaming settings** — configured per [location](/capabilities/connection/location-configuration)
* **A service level agreement** — where you've committed response times to a site owner
* **The installation partner** — recorded on each site
At least 24 hours before migration day, check the site details and EVSE IDs in Connect against your collected data. An EVSE ID that doesn't match what you configure on the charger stops the two from binding, and finding that on the day costs you the window.
### Coordinate roaming
Roaming is tied to your CPO operator prefix, such as `DE*SPI`. Before roaming works under Spirii, the prefix has to be registered with your national registry and approved by the roaming hubs. See [Roaming connection](/capabilities/roaming/roaming-connection).
Moving roaming exposure between platforms involves the hubs and your current provider, so plan it with your Spirii representative well before your first batch. Line up two things alongside it:
They need to push outstanding CDRs to the hubs for settlement before roaming moves. Sessions left unsent are sessions you don't get paid for.
Where your operator prefix changes, the IDs printed on your chargers no longer match the IDs in the platform. Replacing those labels is yours to organise, and it carries driver-facing identification requirements on public sites.
Roaming data propagates on the hubs' own schedule, so expect a short delay before external networks reflect the change.
### Prepare the configuration
The OCPP settings a charger needs are the same across manufacturers; only the place you enter them differs. Your manufacturer's backend or local configuration environment is where they go.
| Setting | Value |
| - | - |
| OCPP version | OCPP 1.6 JSON |
| Central system hostname | `wss://ocpp.spirii.com` |
| Central system port | `443` |
| Secure central system connection | On |
| TLS version | TLS 1.2 (required by `wss://ocpp.spirii.com`) |
| Charge point identity | The charge box ID (CBID), matching Connect exactly |
| OCPPJ password | Empty |
| Reconnect interval | `30` |
| Websocket ping interval | `30` |
| Metervalues during charging sessions | `60` |
| Metervalues referenced to clock | `900` |
| APN, where a Spirii SIM is used | `onomondo` |
Reaching the endpoint also needs the AWS Root CA certificate and the security profile settings. Your Spirii representative supplies the current ones alongside any model-specific recommendations.
### Set up a support channel
Open a shared channel across everyone involved — your operations team, your installer, your hardware manufacturer, and Spirii — and get it in calendars at least a week ahead. A charger that won't connect often needs two parties in the same conversation. On an assisted migration, a weekly meeting through the project keeps the batch plan and its open items in one place.
## 2. Migration test
A migration test is mandatory for any network above five chargers, and worth running below that. Moving a small batch first finds the problems that only appear on your hardware, in your configuration, and settles the process before it runs at volume.
The cut-over itself is a handshake between something you created and something your installer configures:
```mermaid theme={null}
flowchart LR
A("Charge box created in Connect, Pending") --> D("Identities match on the charge box ID")
B("Charger on your previous CPMS") --> C("OCPP endpoint repointed to Spirii")
C --> D
D --> E("Charge box Online, connectors populated")
```
A charger offline on your current platform can't be repointed remotely. Resolve those before the window opens.
Set the units unavailable on your current platform, or run the window outside trading hours, so no driver is mid-session when the connection moves.
Apply the settings above, with the charge point identity matching the charge box ID in Connect.
The charge box moves from **Pending** to **Online** and populates its EVSEs and connectors from what the charger reports. [Charger activation](/capabilities/connection/charger-activation) covers the handshake and what a box still Pending means.
At the location, work through every method it offers: an app session, an RFID charge key, a contactless tap at the terminal, and a roaming session. Each should produce a charge detail record priced by the location's tariff.
The test batch is good when you have:
* Every charge box **Online** with the right connectors beneath it
* A priced CDR from each authentication method the site offers
* Consumption, duration, and power recorded correctly on those records
* The location showing correctly on the map in Connect
Carry what you learn into the plan. A configuration value that needed adjusting on one model needs it on every unit of that model.
## 3. Migration
Move the rest in batches, each running the same sequence as the test. A week of validation per batch is the standard pace, and you can compress it, or run fewer and larger batches, according to how much risk you're willing to carry.
Group batches by hardware model. Units of one model behave the same way through the cut-over, so a configuration adjustment found on the first unit applies across the batch, and the charge boxes come online with the same connector layout beneath them. Grouping by site instead splits a model across windows and repeats the same discovery each time.
Chargers needing a technician on site are their own batch, scheduled around site access rather than around the remote work.
A cut-over draws a clean line through the session record. Sessions that started before it finish on your previous platform and their records stay there; every session after it belongs to Spirii and produces a charge detail record in Connect. There is no partial session split across the two platforms.
## Migrating charge keys
Charge keys migrate in the same window as the chargers, and after them, so there are working chargers to authorise against.
An RFID charge key's UID is physical and doesn't change, so the same card keeps working — you re-register it in Spirii rather than reissuing it to the driver. Create the charge keys in Spirii first, then deactivate them at your previous provider. A charge key live in both platforms can behave unpredictably, since which system authorises it depends on the charger it's presented to.
Each charge key needs a billing customer, a type, its UID, and a label. Carry your existing labels across, or set new ones in Connect. Charge keys that authorise on roaming networks need the label format described in [Charge key authentication](/capabilities/access/charge-key-authentication), which also covers issuing and managing them.
Bulk upload in Connect takes a CSV of up to 100 charge keys per upload, so a larger fleet is either several uploads or a run through the [tokens API](/api-reference/tokens/create-a-new-token).
## 4. Post-migration
Migrated chargers need watching against real traffic. Verify each of these once drivers are using the network:
* **Connect** — sessions and charge detail records landing, with correct consumption and pricing
* **Driver apps** — the location visible, with the right details, in Spirii Go or your branded app
* **Charge keys** — RFID and virtual charge keys authorising as expected
* **Roaming** — inbound sessions from external networks arriving and settling
* **Payment terminals** — transactions capturing rather than only pre-authorising
* **Support** — your own support line reaching the right people for a migrated site
* **Charger screens** — branding and on-screen content correct
Check that authentication is enabled on every migrated charger, and that it isn't accepting all RFID charge keys. A charger that allows charging without authorisation delivers energy normally and produces sessions marked `Unauthorized`, `NoTag`, or `NoUID`, which are excluded from your payout. The charging looks fine and the revenue never arrives. Look for those sessions in your charge records and in the payout specification file.
Physical work runs alongside this phase: replacing the EVSE ID labels where your prefix changed, and updating branding on charger screens. Neither blocks a migration test, and both belong on the list before a site is fully live. Screen graphics come from you; Spirii applies them after migration.
The phase closes when two billing runs have been validated. That's the real proof: sessions priced correctly, the payout matching your own figures, and exclusions explained. See [Understanding your payout](/capabilities/billing-payouts/payouts) for reconciling the invoice against the specification file.
## Next steps
The full flow for a single charger: customer, location, charge box, and first charge.
Running a migrated public charging site: coverage, reliability, power, and payout.
How a charge box binds to a physical charger, and why one stays Pending.
Publishing your chargers to external networks, and the data they require.
# Payment terminal with Spirii POS
Source: https://docs.spirii.com/guides/payment-terminal-setup
Register, configure, and go live with a Spirii POS terminal at your charging location.
Take a Payter Apollo terminal from unboxing to its first live transaction, running Spirii POS.
Running a charger manufacturer's POS or a third-party POS instead? Many of these steps look similar, but the registration and acquiring differ. See [In-person payments](/capabilities/payments/in-person-payments) for how those routes work, and check your provider's own instructions.
## Before you start
Decide which mode applies to your setup, because it changes the acquiring step and the PCI-DSS obligations on your side.
| Mode | Who handles acquiring | Who is the Merchant of Record |
| - | - | - |
| **Turnkey** | Spirii requests the Merchant ID (MID) | Spirii |
| **PAAS** | You bring your own acquiring agreement | You |
If you are not sure which mode you are on, check with your Spirii account manager.
Hardware and acquiring can also be arranged separately through your account manager, for example a Payter Apollo you source yourself on Spirii's Merchant ID. Where they are split, follow the Merchant ID and merchant steps for whoever holds the MID.
Two steps below depend on a third party and set the pace of the whole setup — obtaining the MID, and registering with Payter. Start them before the hardware arrives if you can.
## Steps
Confirm you have received:
* Payter Apollo terminal units
* Mounting hardware: bracket, pole mount, or charger-integrated housing, as applicable
* Power and data cables, where applicable. Some charger-integrated setups use the charger's own connectivity
Do not mount the terminal yet. Registration needs the serial number printed on the device, and it is easier to read before the unit is on a pole.
The terminal needs a Merchant ID from a payment service provider (PSP) to process payments. One MID is needed per location.
**Turnkey:** give Spirii the location details, meaning address, country, and expected transaction volume. Spirii requests the MID from the appropriate PSP for that country.
**PAAS:** obtain a MID from your own PSP, such as Worldline, Elavon, or another provider compatible with Payter. Pass the MID to Spirii so it can be linked to the terminal.
Every terminal is registered with Payter before it can process payments. Register it through Spirii Connect, or through the Payter portal (MyPayter) directly.
In the Payter portal, log in at [payter.com/registration](https://www.payter.com/registration) and enter the terminal serial number together with the MID from the PSP.
Go to **Payment Terminals**, select **Add terminal**, and set:
1. The terminal's **serial number**
2. The **location** and the **charge boxes** the terminal takes payment for
3. The **merchant**, whose name appears on driver receipts: Spirii under turnkey, or your own business under PAAS
See [Payment terminals](/components/commercial/payment-terminals) for what else the record controls, including kiosk mode where one terminal serves several charge boxes.
If drivers will tap charge keys at the terminal as well as cards, the terminal also has to be set to read them. Check with Spirii that charge key reading is switched on. See [In-person payments](/capabilities/payments/in-person-payments).
The terminal has to be online to authorise card payments. A terminal without connectivity cannot take a transaction at all.
* **SIM, Spirii-managed or built-in:** confirm the SIM is active and the terminal shows a signal indicator
* **LAN via the charger:** confirm the charger's network connection is up and the terminal is connected over Ethernet
## Verify
Complete a test transaction before the terminal takes real money.
1. Tap a Visa or Mastercard test card, or your own card if no test card is available
2. Confirm the pre-authorisation appears on that card's statement. The PSP sets that amount, and the terminal shows it to the driver before they tap. See [Pre-authorisation and capture](/capabilities/payments/pre-auth-capture)
3. Start and stop a session, then check it in Connect
4. If drivers will use charge keys here, start and stop a session with one too, and check that it appears in Connect against that charge key
The session appears in Connect and the **final amount is captured**, not left sitting as a pre-authorisation. If the reservation appears but the capture does not, the OCPP link between terminal and charger is the place to look.
## Go live
Confirm the mounting is secure and the screen sits where a driver can reach it. Then watch the first real transactions in Connect or the Payter portal to confirm sessions and payments are recording correctly.
## Replacing a terminal
To swap a terminal out, for example when one is damaged or stolen:
1. Deactivate the old terminal in Connect
2. Receive the replacement unit
3. Repeat the register, configure, and verify steps above for the new unit
The replacement keeps the same location, charge boxes, and MID. You do not need to request a new MID.
## Next steps
Spirii POS, manufacturer POS, and third-party POS, and what each one asks of you.
The terminal record in Connect, its merchant, and the charge boxes it serves.
How terminal revenue reaches you, in turnkey and in PAAS.
What a terminal receipt carries, and how a driver retrieves one later.
# Public charging hub
Source: https://docs.spirii.com/guides/public-charging-hub
Unlock your public charging hub with Spirii.
Most of a public hub's return is decided by its configuration rather than its capacity, and configuration can be changed at any point in the site's life.
## Overview
A public hub succeeds on three things.
Consistent, intuitive, and reliable charging.
Successful capture across every method.
Energy bought cheaper than it's sold.
This guide takes you through the end-to-end flow:
Set the site up, and settle the choices that shape what it can do later.
Prove every payment channel with real sessions while drivers still see the site as out of service.
Tune coverage, reliability, and power against what the data shows.
Receive the revenue, distribute any site-owner share, and meet your obligations.
The last two repeat for as long as the site operates.
## Before you start
For an operator running or taking over public charging sites on Spirii. Grid connection, civil works, hardware, and installation sit with you and your installer. At least one charge box should be online first; [Quick start for CPOs](/guides/cpo-quickstart) covers that.
**Who owns the site** decides where the location sits in your [customer hierarchy](/capabilities/account/customer-management), and with it how you reach the charge boxes for firmware, who receives which share of the payout, whose VAT number appears on a terminal receipt, and which service commitment the site carries.
On your own site, that means one payout, your VAT, and your service commitments. On a customer's site, where a retailer, fuel-station group, or municipality owns it, you [impersonate](/capabilities/account/impersonation) them to reach their charge boxes, split the payout, and bind the agreement you made with them.
**Which payment channels you can offer** sets the ceiling on utilisation. There are four: in-person, in-app, roaming, and charge key billing. Establish the terminal first, since an existing multi-year merchant contract can decide it for you. [Coverage: every way a driver can pay](#coverage-every-way-a-driver-can-pay) compares them.
## Configure
### Upfront decisions
Four choices shape what the site can do later, and each takes a site visit, a renegotiation, or a re-registration to change.
| Decision | Consequence | Documented in |
| - | - | - |
| Charger model | Plug & Charge, remote firmware updates, energy management, and embedded terminals depend on the model's hardware and firmware supporting them. Where they don't, changing what the site can do means changing hardware. | [Charger activation](/capabilities/connection/charger-activation) |
| Connector identifiers | Roaming networks reject IDs outside the eMI3 format, and the format derives from your operator prefix. Correcting them on a live site means re-publishing to every network. | [Roaming connection](/capabilities/roaming/roaming-connection) |
| Merchant of Record for terminals | Turnkey folds terminal revenue into your Spirii payout. PAAS keeps you the merchant, and those sessions fall outside the payout because funds reach you through your own payment service provider (PSP). Switching means a new merchant ID. | [In-person payments](/capabilities/payments/in-person-payments) |
| One location or several at one site | Separating groups of chargers so they can carry different prices or access means running more than one location at the address. Rearranging later moves charge boxes, and a moved box starts fresh: its history stays behind. | [Location configuration](/capabilities/connection/location-configuration) |
Spirii validates models per capability, so confirm support for each capability you intend to use before you commit hardware.
### The configuration checklist
All of this has to be in place before the site is discoverable.
Drag the pin to the bays, not the entrance. Coordinates are what drivers navigate to and what roaming networks receive.
Both are required before the location reaches roaming networks.
Publicly available, and enabled for roaming. Publishing controls discovery, not permission; who may charge is [Location access](/capabilities/access/location-access).
Needed if the site isn't open around the clock. Outside them, only a driver whose charge key or voucher is tied to the location can charge.
Where you've committed response times to a site owner. See [Service level agreements](/capabilities/operation-monitoring/service-level-agreements).
An update takes each charge box out of service for ten to fifteen minutes and can't be rolled back. See [Firmware management](/capabilities/operation-monitoring/firmware-management).
Such as `DE*SPI`, registered with your national registry. Connector IDs derive from it.
### Pricing a hub
Start with a **fixed** base fee. A driver leaving a motorway decides in seconds whether to stop, and a price they can read and trust does more for utilisation than one tracking the market. Fixed also gives you a stated price for a site host or a tender, and makes the AFIR price-transparency obligation straightforward.
Fixed doesn't mean flat. Set the base fee at your overnight rate, then layer energy fees onto daytime and peak timeslots so the price rises with demand and your own costs. The driver still sees one clear price per kWh when they plug in, gross and including VAT.
Conditional fees also manage bay turnover: a time fee switching on after 180 minutes moves a finished driver along, and the app warns them first. [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic) covers how fees stack and resolve.
Choose a **dynamic** base fee instead where your energy contract is spot-linked and margin protection matters more than a predictable price.
A dynamic tariff carries the raw electricity spot price only. Local taxes, grid fees, and regional add-ons sit inside your markup, so a markup set as though spot were your delivered cost will not cover them.
The [roaming tariff](/capabilities/pricing/pricing-options-and-logic#roaming-pricing) is separate: one flat rate per kWh, entered gross but billed net to eMSPs, and effective at the next midnight rather than immediately. Partners add their own margin on top. Plan roaming price changes on a 24-hour cycle, and account for the platform fee so the margin you intend is the margin you get.
## Validate
To make a clean launch, publish the location and enable roaming, but hold each EVSE in **Commissioning** — a [temporary EVSE status](/capabilities/operation-monitoring/temporary-evse-status) that changes only what drivers see. Apps and Hubject show Out of Service; OCPI partners see Planned. The charger stays fully live underneath.
That gives you a site published, connected to the roaming ecosystem, and running real sessions on real hardware, with no driver able to arrive while you work. Prove the pipeline, fix what doesn't hold, then open a site that already works.
Set the status on each EVSE with a start and an optional end, in Spirii Connect or through the [temporary EVSE status API](/api-reference/temporary-evse-statuses-v2/create-a-new-temporary-evse-status).
An app session, an RFID charge key, a contactless tap, and [Plug & Charge](/capabilities/access/plug-and-charge) where enabled. Each should produce a charge detail record priced by the location's tariff. A voucher gives your commissioning team access and a set rate without opening the site to anyone else. See [Voucher access](/capabilities/access/voucher-access).
Tap a card, start and stop a session, and check the final amount is captured rather than left as a hold. A pre-authorisation with no capture behind it points at the Open Charge Point Protocol (OCPP) link between terminal and charge box. The hold is set per location and currency, and adjusts incrementally as the session runs. See [Set up a payment terminal](/guides/payment-terminal-setup).
A session started through another network's app or charge key tests your identifiers and roaming tariff end to end. It should appear on your network and generate a CDR flagged as roaming.
Open the [receipt](/capabilities/compliance/receipts) link for the terminal session on connector `DE*SPI*E00012345*1` and confirm the merchant details and VAT are what you expect.
Remove each temporary status, or let the period expire. Displayed status reverts to the charger's real state, and the site goes live to drivers and roaming partners at once.
The site is ready when you have:
* A priced CDR from every channel you intend to offer
* A roaming session settled through a partner network
* A receipt or statement that resolves for each channel
## Operate
Utilisation and reliability move a hub's return more than capacity does. Three levers change them.
### Coverage: every way a driver can pay
Most drivers arriving at a public hub don't have your app, which makes contactless a requirement rather than an upsell. Public charging in the EU also carries an ad-hoc payment obligation under the Alternative Fuels Infrastructure Regulation (AFIR). [Billing and payout flows](/capabilities/billing-payouts/billing-and-payout-flows) compares the four channels side by side.
The channel a hub can least afford to be without.
No hardware, and the channel your own drivers use. Spirii is always Merchant of Record.
Reaches drivers who will never install your app. Plug & Charge settles here too, priced by the location's tariff.
Fleet and corporate drivers on an RFID charge key, billed to their employer.
Enabling Plug & Charge reboots the charge box, so schedule it when no connector is in use.
### Reliability
An unreliable bay costs more than the sessions it loses, because a driver who fails to charge doesn't come back.
Every connector with its connectivity, status, power, and last error code. Read connectivity and status together: a faulted connector on an online charge box tells you what's wrong, while a status beside an offline box is only the last one it sent. State of charge appears on DC charging where the charge box forwards it, which separates a slow session from one charging as designed.
See [Live status tracking](/capabilities/operation-monitoring/live-status-tracking).
What a first-line response reaches for. Try a soft reset before a hard one. Remote start is the only way to authorise a session without a physical action at the charger, so it's the tool for a driver on the phone. Unlock connector is the exception: on CCS the vehicle holds the lock, so it may not succeed.
See [Remote commands](/capabilities/operation-monitoring/remote-commands).
When a bay needs work, choose deliberately. Setting a connector Inoperative takes it genuinely out of service. A temporary Maintenance status changes only what drivers see, leaving the unit live for a technician on site.
Where you've committed response times to a site owner, record them as a [service level agreement](/capabilities/operation-monitoring/service-level-agreements) bound to the location. Create your default before you add locations: new locations inherit it at creation, and changing it later doesn't rebind the ones already on the old one.
### Power and energy cost
[Energy management](/capabilities/energy-management) works at the location, on the circuit the chargers belong to.
Stays on. It distributes power within the circuit's fuse limit and rebalances as chargers come and go, which lets you add outlets inside an existing grid connection instead of paying for an upgrade.
Where a hub with its own generation gets full value. It opens the chargers to your energy management system (EMS): the EMS watches solar output, battery state, building load, or price, sends dynamic limits to Spirii, and the platform applies them per charger. Charging follows solar through the day, leans on the battery at peak, and holds the site inside its connection limit. Paired with load balancing, the circuit limit itself flexes with local conditions rather than sitting at a fixed ceiling, which is advanced dynamic load management.
Spirii exposes the limits; the EMS is yours to bring.
Load balancing always wins on precedence, so the fuse is never at risk whatever your EMS asks for. Prioritised charging has no effect unless a limit is already active, since there's nothing to prioritise while every charger can deliver full power.
### What to measure
The [Dashboard](/capabilities/reporting-analytics/dashboard) carries sessions, energy delivered, active users, occupancy, uptime, and a heatmap of the busiest hours, each figure set against the preceding window. Read the metric definitions there before reporting any figure onward, particularly uptime, which measures something narrower than the word usually implies.
For what the page can't answer, use [exports](/capabilities/reporting-analytics/exports). The **Dashboard export** writes one row per connector per day, which finds the underperforming outlet inside a healthy-looking site. The **charge detail record export** carries each session with its tariff, fee breakdown, and VAT split, for utilisation analysis and reporting to a site owner. The **charge detail records API** returns the same data as a feed, for reporting you run monthly.
Two things to watch. The heatmap counts a session at the hour it **ended**, so a long session lands in one block: read it as when bays free up. And sessions ending with almost no energy delivered appear in your payout specification file as an exclusion, which makes that file a good place to spot a charger accepting drivers and then failing to deliver.
## Settle
Roaming revenue is paid out in the same month Spirii invoices the roaming partner; app, terminal, and charge key revenue follows the month after.
The document is a **self-billing invoice** Spirii raises on your behalf, one per country and currency, with a single consolidated line. You don't invoice Spirii, and you don't invoice roaming partners or eMSPs for sessions Spirii collected on. Self-billing follows when a session **ended**, so one completing late, or arriving late because a charge box was offline, lands in the earliest open period.
A **specification file** lists every CDR, included and excluded, and is what you reconcile against. Three exclusions recur at a public hub: sessions under 0.2 kWh, sessions where the charge box allowed charging without authentication, and terminal sessions under your own acquiring agreement. [Understanding your payout](/capabilities/billing-payouts/payouts) covers the full list and the method. Platform and payment fees arrive on a separate invoice rather than line by line.
Where a site owner takes a share, configure the split on the location and Spirii issues each party their own self-billing invoice, with no manual transfer between you. See [Revenue sharing](/capabilities/billing-payouts/revenue-sharing).
Every session also produces a driver-facing document: a [receipt](/capabilities/compliance/receipts) carrying VAT where the driver paid at the moment of charging, a statement where the session is invoiced afterwards, as roaming and charge key sessions are. You can add up to 200 characters of your own text to receipts, set on the customer that owns the location, for a support number or compliance wording.
A public location in an AFIR member state also carries a reporting obligation: static and dynamic infrastructure data published to your member state's National Access Point, which Spirii provides as DATEX II endpoints. See [AFIR compliance](/developers/afir-compliance).
## Continuous optimisation
A hub is never finished, only re-tuned. A tariff that held through your first quarter may not hold when a competitor opens two junctions away, a bay faulting twice a month is a hardware conversation rather than a support one, and adding outlets sends you back through the upfront decisions.
The monthly rhythm is short. Read the Dashboard against the preceding period, pull the connector-day export wherever a figure looks wrong, reconcile the payout against the specification file, and act on whichever lever the data points at.
## Next steps
Heavy-duty public charging, and what changes when the vehicle is a truck.
Register, configure, and go live with a terminal at the site.
Configure the split where a site owner takes a share.
Distribute and schedule charging power across the site.
# Set up revenue sharing
Source: https://docs.spirii.com/guides/revenue-sharing-setup
Configure Spirii to pay a site owner directly for the revenue generated on their chargers.
Have Spirii pay a site owner their share of the charging revenue automatically each month, so you never move the money yourself.
## Before you start
This is for a CPO running chargers on behalf of someone else: a retailer, a hotel, a landlord, or any business that owns the location. Confirm three things first.
* The site owner has a billing entity configured in the Spirii Business Portal
* The split is agreed between you, as a percentage or a rate per kWh
* The site owner's bank details are registered with Spirii
The split can be expressed either way, and they behave differently. A percentage tracks the tariff you charge drivers, so the site owner's return moves when your price does. A rate per kWh is a fixed net amount — paid regardless of what the tariff does. See [Revenue sharing](/capabilities/billing-payouts/revenue-sharing).
## Steps
In Spirii Connect, check that your payout settings tell Spirii to issue self-billing documents to site owners, and that revenue sharing is enabled.
The share sits on a **financial agreement**, attached to the location the chargers belong to. Create one while [setting the location up](/capabilities/connection/location-configuration), or link an existing agreement afterwards.
Set the share on the agreement as a percentage of the tariff, say 15%, or as a net rate per kWh, say 0,10 EUR.
Confirm that the locations appear under the correct billing entity in Connect, that the payout recipient is the site owner, and that the split matches what you agreed.
## Verify
The first real confirmation comes at the end of the billing period, when the documents are produced.
Two self-billing invoices are issued for the period: one to the site owner for their share, and one to you for the remainder. Each party is paid into their own registered bank account, with no transfer from you.
If only one document appears, the financial agreement is the place to look: either it is not attached to the location, or the payout recipient is still resolving to you.
## Keeping it current
If the site owner's bank details change, tell Spirii before the next billing cycle closes. A cycle that closes on the old details pays out on the old details.
The commercial agreement behind the split stays yours. Spirii pays out exactly as configured and does not mediate a disagreement with the site owner about what the share should have been.
## Next steps
How the split works, and what it depends on.
How to read a self-billing invoice and reconcile it against Connect.
Where a financial agreement is attached to a location.
How the billing engine decides who is paid what.
# Truck charging
Source: https://docs.spirii.com/guides/truck-charging
Unlock depot and on-the-road charging for your heavy-duty fleet with Spirii.
Charging is one of the biggest running costs in an electric truck fleet, and how the depot is set up decides both what it costs and whether the trucks leave on time.
## Overview
Truck charging succeeds on three things.
Every vehicle charged and ready when its shift starts.
Drivers authenticating without friction.
Energy bought at the cheapest hours.
The four phases below take a depot from configuration to cost allocation:
Set the depot up, and settle the choices that shape how far it can scale.
Confirm each vehicle is recognised and a full charging window finishes before shift start.
Charge to the duty cycle, keep the fleet moving, and hold energy costs down.
Allocate charging cost across the fleet, and collect revenue where you've opened the site.
The last two repeat for as long as the depot operates. A final section covers the same fleet charging out on the road.
## Before you start
This guide is for an operator running a heavy-duty or medium-duty electric fleet:
* Logistics companies
* Freight carriers
* Distributors
* Municipal fleets
Grid connection, civil works, hardware installation, and vehicle procurement sit outside it. [Quick start for fleets](/guides/fleet-quickstart) is the shortest path to a working depot if you want that first.
**Who owns and operates the chargers** shapes where the depot sits in the platform.
On a site you own or lease. The location sits under your own account.
Your fleet charges as their customer. You sit in their hierarchy, and they set the tariff and access.
The landlord takes a share of what the chargers earn.
Settle this before you configure anything. It decides who holds the operator role, who receives any payout, and whose service commitment covers the site.
## Configure
### Upfront decisions
| Decision | Consequence | Documented in |
| - | - | - |
| Circuit design and groundwork for your future fleet | Load balancing shares out whatever the circuit allows. Size it for today's fleet and growing later means new electrical work. Digging up the yard a second time is the costly part, so lay cable and ducting for the bays you expect while the ground is open. | [Energy management](/capabilities/energy-management) |
| Charger model | Load balancing, scheduled charging, Autocharge, and grid balancing each depend on the model supporting them, and grid balancing is validated to a higher bar than charging alone. | [Grid balancing](/capabilities/energy-management/grid-balancing) |
| Authentication method | Autocharge identifies a vehicle by its VIN or MAC address and only works on chargers managed by Spirii's platform, not over roaming. Drivers who charge away from the depot need a roaming-enabled charge key as well. | [Charge key authentication](/capabilities/access/charge-key-authentication) |
| Who the site is open to | Moving between access tiers is straightforward, and each carries different pricing, regulatory, and access-management work. | [Location access](/capabilities/access/location-access) |
### Choose an access tier
A depot doesn't have to be closed. These three tiers cover most cases, differing in who can find the site and who can charge there.
| Tier | Who can charge | How you set it |
| - | - | - |
| Private | Your own fleet, and anyone you admit deliberately | Leave the location unpublished, bind a charge key group to it, and issue vouchers for partner fleets |
| Public within opening hours | The public during the hours you set; your fleet at all times | Publish the location and define [opening hours](/capabilities/connection/location-configuration#opening-hours). Outside them, only a bound charge key group or a voucher authorises |
| Fully public with roaming | Any driver, including drivers arriving from other networks | Publish the location, enable roaming, and set both a tariff and a roaming tariff |
A private depot declines an ordinary registered charge key, so admitting anyone beyond your own fleet means adding their charge keys to a bound group or issuing them a [voucher](/capabilities/access/voucher-access). A voucher carries its own price, which is how a partner fleet charges at a negotiated rate while your own pricing stays untouched.
Opening hours are the tier worth understanding before dismissing it. A depot whose trucks are out between 06:00 and 18:00 has capacity sitting idle through the working day, and other logistics operators nearby have vehicles that need charging in exactly those hours. Publishing the site for that window turns an idle asset into a partnership: local fleets charge at a rate you set, your own drivers keep guaranteed access around the clock, and neither of you pays for infrastructure you only need part of the day.
### Set up authentication and pricing
Issue each driver or vehicle a charge key: RFID for a card, virtual for an app, or vehicle for Autocharge by VIN or MAC address. At a depot, Autocharge removes the friction entirely, since a driver plugs in and walks away without finding a card at 05:00. See [Charge key authentication](/capabilities/access/charge-key-authentication).
Every location bills against a tariff, including a depot charging its own fleet, where a free tariff is the usual answer. Where you've opened the site, the public tariff and any voucher tariffs sit alongside it. See [Pricing options and logic](/capabilities/pricing/pricing-options-and-logic).
Autocharge only works on chargers managed by Spirii's platform, not over roaming, so a vehicle relying on it at the depot won't be recognised on another operator's chargers. Any driver who charges away from the depot needs an active, roaming-enabled charge key as well.
You set scheduled charging up yourself in Spirii Connect. The rest of energy management — load balancing and programmatic charger control — is enabled on a location by Spirii, so ask your Spirii representative to factor it into your timeline rather than assuming it's ready on the day.
## Validate
Before the depot carries a shift pattern, confirm it behaves for the vehicles that depend on it.
Autocharge identifies a vehicle by its VIN or MAC address, and whether a given truck presents one reliably varies. Test each vehicle at the charger instead of trusting a specification sheet.
Charge a vehicle from its typical return state to the level its route needs, inside the window you plan to use. This is what tells you whether the circuit, the charger power, and the window length agree with the duty cycle.
On a private depot, confirm a charge key inside the bound group charges and one outside it is declined. Where you've published the site, check the hours behave as you set them.
A session started by `EVBUS.0007` at `Munich DC Hub` should produce a charge detail record carrying that charge key and the customer it belongs to. That attribution is what cost allocation depends on later.
The depot is ready when you have:
* Every vehicle recognised by its own charge key or Autocharge identifier
* A full charging window completing inside the time available
* Access behaving as configured for your chosen tier
* Sessions attributing to the right vehicle and cost centre
## Operate
Three levers carry the cost of running a depot and the reliability of what leaves it: the charging schedule, the power available, and how quickly you know something has failed.
### Charge to the duty cycle
Trucks sit plugged in far longer than they need to charge, and that slack is what a depot runs on. Charging windows use it in one of two ways: you set the window yourself, or you set the hours and an end time and let the platform pick the cheapest intervals inside them. Either way the vehicle is full before the window closes, and the energy is bought when it costs less. [Energy management](/capabilities/energy-management) covers the mechanics.
Where some vehicles have to be ready whatever else is happening, prioritised charging gives a vehicle with a priority charge key maximum power first. It takes effect only while a power limit is active, so it works alongside load balancing.
### Get more out of the connection you have
[Load balancing](/capabilities/energy-management) distributes power across the depot within the circuit's fuse limit, which is what lets you add chargers inside an existing grid connection instead of waiting on an upgrade. In markets where connection queues run long, that wait is often what limits fleet growth.
Programmatic charger control opens the depot to your own energy management system, so on-site solar and battery storage drive charging directly: charging follows generation, leans on the battery at peak, and the site stays inside its connection limit. A battery is also how some depots avoid a connection upgrade altogether.
A depot fleet charging between shifts suits [grid balancing](/capabilities/energy-management/grid-balancing), which earns revenue for brief adjustments to charging power when the grid needs them. You control the vehicles and the schedule, so you know how much slack there is to sell, and you choose the hours you expose. That page carries the market, hardware, and portfolio requirements.
### Monitor the depot
A charger that failed overnight is a truck that doesn't leave.
The Monitoring list carries every charge box currently offline and every EVSE reporting a fault. Alerts email you when either happens, so for a depot the one that matters arrives before the morning shift rather than after it.
See [Faults and alerts](/capabilities/operation-monitoring/faults-and-alerts).
Filtered to the depot, the Connectors page is a bay-by-bay view: what each vehicle is drawing and its state of charge, where the charge box reports it. That's how you tell a vehicle that will be ready on time from one that won't.
See [Live status tracking](/capabilities/operation-monitoring/live-status-tracking).
Where the depot feeds dispatch or route planning, the same live data is available through the [API](/developers/fleet-management), including state of charge and expected readiness per vehicle. That's how charging state reaches your transport management or telematics system.
## Settle
A depot charging its own fleet on a free tariff produces no payout, so settlement here is about cost rather than revenue: what each vehicle, driver, or sub-fleet consumed, at the depot and on the route, and what it cost.
Model the cost centres you want to report on as customers, and link each charge key to the one that should carry it. Every session then produces a charge detail record carrying the charge key and the customer, so an [export](/capabilities/reporting-analytics/exports) splits consumption by vehicle, driver, or depot without joining it to anything else. The [Dashboard](/capabilities/reporting-analytics/dashboard) covers depot utilisation over a period.
On-road charging is where the cost sits. Sessions your drivers run on other operators' networks reach you as a single consolidated invoice from Spirii covering all outbound roaming, rather than separate bills from each network your trucks happened to stop at. Sessions on Spirii-connected chargers outside your own sites are billed the same way, against the charge key that started them and to the customer it belongs to. Both land in the same records as depot charging, so cost per vehicle covers the whole route and not just the yard. See [Roaming settlement](/capabilities/billing-payouts/roaming-settlement).
Where you've opened the depot, revenue reaches you as it does at any public location: Spirii collects and pays out monthly via a self-billing invoice, net of platform and payment fees. See [Understanding your payout](/capabilities/billing-payouts/payouts). Where a property owner takes a share of what the chargers earn, configure the split on the location and each party receives their own invoice — see [Revenue sharing](/capabilities/billing-payouts/revenue-sharing).
## On the road
The same drivers charge away from the depot, on other operators' networks, with the charge keys you already issued.
Enable roaming on each charge key, keep it active, and label it in the format [Roaming connection](/capabilities/roaming/roaming-connection) describes. An incorrectly labelled charge key is a common reason a driver can't charge on another network. Autocharge only works on chargers managed by Spirii's platform, not over roaming, so a vehicle relying on it at the depot needs a roaming-enabled charge key for the road.
Drivers find charging through Spirii Go or your branded app, where the map covers your own sites alongside public and roaming chargers. A heavy-vehicle filter narrows it to sites that suit the vehicle, across truck with trailer, rigid truck, bus, and semi-tractor, so a driver isn't routed somewhere their vehicle can't physically use. What appears depends on the vehicle types each operator publishes for their sites. In Connect, the Charge map shows the same coverage for planning a route. See [Network coverage](/capabilities/roaming/network-coverage).
Sessions on other networks land back in Connect against the charge key that started them, billed to the customer it belongs to, so on-road charging appears in the same records and exports as depot charging.
## Continuous optimisation
A depot is sized for a fleet, and the fleet changes. Adding vehicles pushes against the circuit before it pushes against the chargers, so revisit the load management design each time the fleet grows, ahead of the day a fuse trips. If the groundwork covers more bays than you built, adding chargers means mounting the units and bringing them online. If it doesn't, the yard has to be opened up again. Duty cycles shift with contracts, which moves the charging windows. And a depot whose utilisation drops is a candidate for opening hours, turning idle bays into revenue without giving up guaranteed access for your own trucks.
The monthly rhythm: check depot utilisation and [uptime](/capabilities/reporting-analytics/dashboard) against the preceding period, pull an [export](/capabilities/reporting-analytics/exports) where a figure looks wrong, review consumption per vehicle against what the routes should require, and act on whichever lever the data points at.
## Next steps
The shortest path: a private depot and drivers on the road.
Running a fully public charging site, if you open the depot commercially.
Earn from the flexibility in a depot charging between shifts.
Admit a partner fleet at a negotiated rate without changing your own pricing.
# Spirii Docs
Source: https://docs.spirii.com/index
Learn how to build powerful connections with our all-in-one EV charging platform.
Spirii connects the world's largest CPOs and fleet operators to powerful charging solutions, customers and drivers. Use this space to get an overview of our platform, APIs and how to get started.
Get your first charger online and ready to charge, end to end.
Set up your depot and get your drivers charging on the road.
See how the key components are structured and related in Spirii's platform.
Start building with the Spirii API: authentication, quickstart, and rate limits.
## Popular
Browse every endpoint, with examples and request/response schemas.
See the latest updates, improvements, and fixes to Spirii's platform.
# Platform overview
Source: https://docs.spirii.com/platform-overview
The components the platform is built on, the interfaces you work through, and the roles involved.
These docs are organised around the platform itself:
* **Components** are the platform's core objects (locations, chargers, tariffs, charge keys, sessions), and they map directly to the resources in the API reference.
* **Capabilities** are what the platform does with those objects: roaming, billing, energy management, and the rest.
* **Guides** put them to work end to end, so you can get started straight away.
Charge point operators (CPOs) and e-mobility service providers (eMSPs) share the same components. A location, a tariff, or a session means the same thing to a CPO and to an eMSP, but each reaches them through different endpoints and features. Capabilities connect the two: roaming, for example, takes a location and tariff a CPO has published and makes them reachable to an eMSP's drivers, then settles the session between them.
## Interfaces
The admin web app. Operators manage locations, chargers, pricing, and access; eMSP and fleet admins manage charge keys and drivers.
Build the platform's capabilities directly into your own systems and front-ends.
The driver app (Spirii's own, or an eMSP's branded version) for finding, starting, and paying for a charge.
Spirii's point-of-sale software for in-person card payments, running on Payter Apollo terminals.
## Roles
| Role | Description |
| - | - |
| Charge Point Operator (CPO) | The business that runs the chargers: brings them online, sets pricing and access, and earns the charging revenue. |
| e-Mobility Service Provider (eMSP) | The business that gives drivers access to charging, across its own and other networks. |
| Customer | The organisation that owns locations, chargers, or drivers in the platform. Depending on the use case, this is a fleet, a site or asset owner, or another partner. |
| Driver | The person charging an EV. On the platform, a driver is represented by an app user or a charge key (an RFID, virtual, or vehicle key). |
## Charging
| Component | Description |
| - | - |
| Locations | The container for one or more chargers at a geographical site, and the entity that pricing and access are connected to. |
| Charge boxes | An individual charge box that can serve electricity to one or more EVs at a time. |
| EVSEs | The part of a charge box that can serve one EV at a time. |
| Connectors | The socket or cable a single EV plugs into. |
| Charge detail records (CDRs) | The immutable, billable record of a completed charging session. |
| Sessions | The flow of electricity during a charging session, including sessions still running. |
## Access
| Component | Description |
| - | - |
| Tenants | A single eMSP organisation on the platform — the account boundary that owns its eMSP identities, networks, and subscriptions. |
| Networks | Govern which charging infrastructure an eMSP tenant can reach, and how each connection is established, prioritised, and priced. Spirii's roaming portfolio is published to every tenant by default; a tenant can also keep networks that stay private to it. |
| Charge keys | The authentication ID used to start a charging session: an RFID, virtual, or vehicle key (Autocharge). Shown as charge keys in Spirii Connect. Charge key groups can limit which charge keys charge at selected locations. |
| Vouchers | A code entered in Spirii Go or a branded app to unlock access at selected locations. Voucher groups set the access and price conditions that apply to a user group. |
| App users | A driver with an account in Spirii Go or a branded app. |
## Commercial
| Component | Description |
| - | - |
| Tariffs | The gross price and conditions for charging. Supports flat and dynamic (spot) pricing with conditional fees. A separate roaming tariff sets the price for charging via roaming partners, who add their own margin on top. |
| Payment terminals | The card payment terminals at a location that take in-person payments. Spirii POS runs on Payter Apollo hardware; other terminals and point-of-sale systems are also supported. |
## Where each component is defined
Each object above has its own component page with the full detail: attributes, states, and how it's used. Capabilities act on these objects, and guides walk you through using them end to end.
The full definitions, one page per object.
What the platform does with these objects: roaming, energy management, billing.
Start-to-finish walkthroughs to get you up and running.