JouloDocs

Authentication

Authenticate requests to the Joulo API with an API token or OAuth2

Every request to the Joulo API must include a valid token. The API supports two authentication methods: personal API tokens for simple integrations and OAuth2 for third-party applications.

API tokens

The simplest way to authenticate. Generate a token from the Joulo dashboard and include it in your requests.

Go to Developer → API.

Activate your token

Click Activate to generate your personal API token. Copy it and store it securely.

Store your API token in an environment variable or secrets manager. Never hard-code it in source code or commit it to a repository.

Using the token

Send your token in the Authorization header on every request:

curl https://api.joulo.nl/functions/v1/api/chargers \
  -H "Authorization: Bearer YOUR_API_TOKEN"

The ?token= query-string method that earlier versions of these docs documented is no longer supported and will return 401. Tokens in URLs leak via server, proxy, and browser logs and via the Referer header. Use the Authorization header • Home Assistant's rest: integration supports a headers: block, see the Home Assistant guide.

Token management

  • Rotate your token • Generate a new token from the dashboard at any time. The old token is immediately invalidated.
  • Deactivate your token • Remove API access entirely from Developer → API → Deactivate.

The embeddable ERE widget (Developer → Widget) uses its own token, separate from your API token. That token sits in the widget URL, because an <img> or <iframe> cannot send an Authorization header:

https://api.joulo.nl/functions/v1/widget-badge?token=WIDGET_TOKEN&format=json

The same URL renders the widget itself with format=html (for an <iframe>) or format=svg (for an <img>). Query parameters: variant (card, compact or deel), theme (light or dark), lang (nl or en), hide_earnings=1 to leave the estimated amount out, and for the Deel variant show_link=1 to include the invite link. format=json&deel=1 adds a deel object with the host's sharing status, the best moment and the guest totals. The dashboard (Developer → Widget) writes these snippets for you.

Treat the widget link as a read-only share link:

  • What it shows • Only your totals: kWh, ERE, estimated earnings, CO₂ and your effective fee. No name, address, e-mail, IBAN, charger or individual sessions.
  • What it cannot do • It gives no access to the API and cannot change anything.
  • Scope • One token belongs to one account. It never reveals another account.
  • Revoke • New link replaces the token. Deactivate switches the widget off. Either way the old link stops working right away. A browser that already loaded it can show its copy for up to five minutes.

Use the widget link only to embed the widget. For integrations such as Home Assistant, use your API token in the Authorization header. GET /energy returns your kWh and ERE totals, per month and lifetime. The Home Assistant guide shows the setup.

OAuth2

For third-party applications that act on behalf of Joulo users, the API supports OAuth2 with PKCE (Proof Key for Code Exchange).

OAuth2 tokens use scopes to limit access:

ScopeDescription
chargers:readAccess charger data via GET /chargers
chargers:writeAdd chargers via POST /chargers
sessions:readAccess session data via GET /sessions
energy:readAccess energy statistics via GET /energy
partners:readPartner reads (GET /partner/…): profile, drafts, customers, payouts, dashboard
partners:writePartner writes (POST /partner/…): company info, branding, invites, customer uploads, API-key management

See the OAuth2 guide for the full authorization flow.

Partner API keys

Approved partners integrate server-to-server with a per-partner API key (jpk_live_…) instead of a user token. Keys are minted in the partner portal and can only reach the partner endpoints • see the Partner API section.

Error responses

When a request is made with a missing or invalid token:

{
  "error": "Missing or invalid API token"
}

When a valid OAuth2 token lacks the required scope:

{
  "error": "Insufficient scope",
  "required_scope": "chargers:read"
}
HTTP statusCause
401 UnauthorizedToken is missing, invalid, or expired.
403 ForbiddenToken is valid but lacks the required scope for this endpoint.