JouloDocs

Chargers

Register the account's charger against a MID-certified model from the Joulo catalog.

Chargers

ERE requires MID-metered kWh. Registering the account's charger against a MID-certified model from the Joulo catalog is what makes the account eligible: the catalog carries the verified MID verdict, so you don't assert MID status yourself.

Register a charger

POST /v1/chargers — scope cpo:chargers:write

curl -X POST https://api.joulo.nl/functions/v1/api/v1/chargers \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "60092124-c768-4191-9c9d-55ef3fc49999",
    "catalog_charger_id": "81978554-c5ec-4215-8968-95d34a4e8c68",
    "serial_number": "ACE0013982"
  }'
{
  "ok": true,
  "charger_id": "…",
  "catalog": { "brand": "Alfen", "model": "Eve Double Plus" },
  "mid_eligible": true,
  "account_ere_eligible": true
}

Body

FieldRequiredDescription
account_idyesThe account to register the charger on.
catalog_charger_idone of the twoId of a MID model in the Joulo catalog.
ocpp_vendor + ocpp_modelone of the twoThe chargePointVendor and chargePointModel from the unit's BootNotification. Joulo resolves the catalog model server-side. Ignored when you send catalog_charger_id.
serial_numberfirst charger: no • additional chargers: yesThe unit's serial/meter number. Doubles as the idempotency key from the second charger on.
{
  "account_id": "60092124-c768-4191-9c9d-55ef3fc49999",
  "ocpp_vendor": "eNovates",
  "ocpp_model": "0A000T2N0031231",
  "serial_number": "ACE0013982"
}

The response echoes catalog.catalog_charger_id, so you can cache what the pair resolved to. A pair we cannot place returns 422 catalog_unresolved.

Catalog ids. Resolve them from the BootNotification pair, or look them up with the catalog endpoint below. The model must be MID-certified in the catalog; a non-MID model returns 422 catalog_not_mid. If your model is missing, send Joulo the MID evidence (EU Declaration of Conformity or datasheet showing the built-in MID meter) and we add it.

Catalog ids are per environment. The sandbox and production hold separate databases, so the same model has a different catalog_charger_id in each. Resolve or look up the id in the environment you are calling. Never hardcode one you saw on the sandbox.

Resolve from a BootNotification

GET /v1/catalog/chargers/resolve — any valid CPO token, no specific scope

Pass ?vendor= and ?model= exactly as the charger reported them in its BootNotification. Most brands put a nameplate code in chargePointModel, not the marketing name, so a literal comparison against brand + model never matches. This endpoint runs the same resolver Joulo's own OCPP gateway uses: per-model alias lists, including prefix patterns for SKU families.

curl -G "https://api.joulo.nl/functions/v1/api/v1/catalog/chargers/resolve" \
  --data-urlencode "vendor=eNovates" \
  --data-urlencode "model=0A000T2N0031231" \
  -H "Authorization: Bearer <token>"
{
  "resolved": true,
  "vendor": "eNovates",
  "model": "0A000T2N0031231",
  "catalog_charger_id": "793683e1-b185-4c58-96a0-3b1da599ec8e",
  "brand": "Enovates",
  "catalog_model": "One",
  "mid_meter": true
}

A pair we cannot place is a normal 200 with "resolved": false, plus the brand's MID models as suggestions:

{
  "resolved": false,
  "vendor": "Acme",
  "model": "AC-9000-XYZ",
  "detail": "No catalog model matches this vendor + model. Send Joulo the pair and we add the alias.",
  "suggestions": []
}

Send us the pair and we add the alias, so the next unit of that family resolves for every CPO at once. Do not build your own vendor + model mapping table: it drifts from ours the moment a manufacturer ships a new SKU suffix.

mid_meter. A resolved model is not automatically a MID model. Check this field before you register the charger, or POST /v1/chargers answers 422 catalog_not_mid.

Find the catalog id

GET /v1/catalog/chargers — any valid CPO token, no specific scope

Lists the MID-certified models in the Joulo catalog. Filter with ?search= (matches brand and model, case-insensitive) and page with ?limit (default 100, max 200).

curl "https://api.joulo.nl/functions/v1/api/v1/catalog/chargers?search=alfen" \
  -H "Authorization: Bearer <token>"
{
  "models": [
    {
      "catalog_charger_id": "81978554-c5ec-4215-8968-95d34a4e8c68",
      "brand": "Alfen",
      "model": "Eve Double Plus"
    }
  ],
  "count": 1
}

Multiple chargers, serial-based idempotency. An account can carry up to 10 active chargers (they share the account's connection; monthly kWh sums across them). Re-posting a serial_number we already have returns the existing charger ("idempotent": true) instead of creating a duplicate. Once an account has a charger, serial_number is required for every next registration (409 serial_required) — otherwise a retry and an intentional second charger would be indistinguishable.

account_ere_eligible. Registering the MID charger is usually the last automated gate. When the response returns account_ere_eligible: true, the account has cleared every requirement — validated EAN, signed machtiging, MID charger, and IBAN — and its kWh will count toward ERE. If it's false, one of those is still missing.

Errors

HTTPerror
400invalid_account_id, invalid_catalog_charger_id, vendor_and_model_required
404account_not_found, catalog_not_found
409no_connection (register the account's connection first), serial_required
422catalog_not_mid, catalog_unresolved, charger_limit