JouloDocs

Deliver monthly kWh totals

Stores monthly kWh totals for one connection. A repeat for the same connection and month replaces the stored total, unless Joulo already registered that month as ERE, which locks it. A malformed month is reported as invalid and does not fail the batch.

POST
/v1/sessions:batch
AuthorizationBearer <token>

OAuth 2.0 client credentials for a CPO client bound to one partner. Request a token with grant_type client_credentials and send client_id and client_secret in the body, as JSON or form data. The token endpoint does not accept HTTP Basic client authentication. The token lasts one hour and has no refresh token. Omit scope to get every scope your client holds. The /v1 routes refuse user tokens and personal API tokens.

In: header

Scope: cpo:sessions:write

account_idstring

The account to deliver for. It must be an account you created through this API.

Formatuuid
connection_id?string

Picks the active connection when the account has more than one. Otherwise the first active connection is used.

Formatuuid
source?string

Label for the origin of the data, for example your CSMS name. Trimmed to 40 characters.

Default"cpo_api"
monthsarray<CpoDeliveredMonthInput>

1 to 240 months. Send each month once per batch.

Response Body

curl -X POST "https://api.joulo.nl/functions/v1/api/v1/sessions:batch" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "60092124-c768-4191-9c9d-55ef3fc49999",
    "source": "your-csms",
    "months": [
      {
        "period": "2026-01",
        "total_kwh": 182.4,
        "session_count": 21
      },
      {
        "period": "2026-02",
        "total_kwh": 143.9,
        "session_count": 17
      }
    ]
  }'
{
  "ok": true,
  "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
  "connection_id": "d3547de1-d1f2-4344-b4c2-17169b7526f9",
  "accepted": 0,
  "outside_mandate": 0,
  "locked": 0,
  "invalid": 0,
  "results": [
    {
      "period": null,
      "status": "ingested"
    }
  ]
}
{
  "error": "invalid_json",
  "detail": "string"
}
{
  "error": "Missing or invalid API token"
}
{
  "error": "Insufficient scope",
  "detail": "string",
  "required_scope": "string"
}
{
  "error": "account_not_found",
  "detail": "string"
}
{
  "error": "no_connection",
  "detail": "string"
}
{
  "error": "Too many requests",
  "retry_after_seconds": 0
}
{
  "error": "ingest_failed",
  "detail": "string"
}
{
  "error": "string"
}