API changelog
Every change to the Partner API, the CPO API and the personal API that you may need to act on, newest first.
We change the API often. Almost every change adds something: a new endpoint, a new optional field, a new value in a response. Those changes need nothing from you, as long as your client ignores fields and values it does not know.
A breaking change removes or renames something, or makes a request stricter. We announce each one here first, with the date it takes effect on production. We agree that date with the partners who use the endpoint. Until that date the current behaviour keeps working.
The sandbox runs the same code as production, so it changes on the same day. There is no preview period on the sandbox.
The API reference comes from one OpenAPI description. CI compares every change to it with oasdiff and refuses a breaking change that has no entry on this page.
2026-11-06
- New: a replacement product can cost more in some postal code areas,
because installers there ask more.
GET /partner/replacement-offersgivesbase_price_cents,regional_extra_centsandregional_priceson each product. For one customer,price_centsis now the price at their postal code, andPOST /partner/replacement-orderscharges that price. Nothing changes for a customer outside every area.
2026-11-04
- Changed: we lifted the restriction on customers whose laadstation Road
manages, which we announced on 23 October.
GET /partner/ere-positionsincludes them again, with yourexternal_ref.GET /partner/customersshows them in full again, andmanaged_by_roadisfalsefor every customer. Treat a customer who is missing fromGET /partner/ere-positionsas hidden, not as a failed registration: the customer can have objected to sharing, or revoked your app. ReadGET /partner/draftsfor the claim status. - New:
POST /partner/chargers/disable, for a pre-coupled BlueBird charger that changed owner. It disables the charger on your customer's account and frees itscharger_idfor your next upload. See When a charger changes owner. - Changed:
POST /partner/customersno longer rejects acharger_idascharger_claimedwhen the only account that held it has disabled it.
2026-11-03
- New:
phoneandibanonPOST /partner/customersandPOST /partner/drafts/import. At activation we put both on the customer's account while it holds none, so the registration form opens with them filled in. A value that fails the check is dropped and named in the newcontact_ignoredresponse field. See Sending the phone and the IBAN. - Changed: an auth-link resumes an activated draft while the IBAN on the
account is still the one you sent. Before, any stored IBAN refused the link
with
account_has_details.
2026-11-02
- New:
first_nameandlast_nameonPOST /partner/customersandPOST /partner/drafts/import. At activation we put the name in the customer's profile, so the registration form opens with it filled in. Anamealone does the same when it looks like a first and a last name. See Sending the name. - Changed: in the in-app flow, a customer who couples a charger on our coupling page now returns to the flow by themselves. Before, they stayed in the Joulo dashboard and never reached your return URL. This holds for every brand except BlueBird Power, which couples inside the flow.
2026-10-31
- New:
connection_statusinGET /chargerscan beawaiting_feed, for a SolarEdge charger that waits for its first weekly file from SolarEdge. It readnever_connectedbefore. SolarEdge chargers also carryfeed, with the Sunday the first file should come. See connection status.
2026-10-30
- Changed: a draft whose email address belongs to a customer who already
chose you as energy supplier now becomes
activewithin 15 minutes. Before, we checked only when you uploaded the draft or requested an auth-link, so a customer who missed one condition at that moment stayed oninvited. See the app flow.
2026-10-29
- Changed: when a row in
GET /partner/ere-positionscarries yourexternal_refwithexternal_ref_match: "ean", and the customer signed the authorisation and submitted their registration, we activate your draft on that account. The draft then has statusactiveinGET /partner/drafts, also when it wasclaimed,conflictoractiveon an empty account. The row moves toexternal_ref_match: "claim"andsource: partner_upload. We check every 15 minutes and when you request an auth-link. See the app flow.
2026-10-28
- New:
external_refinGET /partner/ere-positionsalso appears on a customer who did not claim your draft but registered on another Joulo account with the EAN of that draft. We show it only when exactly one Joulo account holds that EAN, our EAN check matched it, the customer picked you as their energy supplier, and the surname in your upload matches the surname on that account. The new fieldexternal_ref_matchsays how the reference got there:claimorean.sourcedoes not change. See ERE positions. - Changed: a customer who revokes your app under Connected apps in their
Joulo account drops out of
GET /partner/ere-positions. Their row inGET /partner/customerskeeps onlycustomer_ref,attached_monthandpartner_share_pct, andhas_chargeris absent. Your share on the customer stays. Signing in to your app with Joulo again brings both rows back. See ERE positions.
2026-10-25
- New: optional
locationonPOST /v1/chargers, the formal address of the charge point:postal_codeandhouse_number, plushouse_number_additionwhen there is one.streetandcityare optional. Joulo compares it with the address of the account's connection and returnslocation_check(match,mismatchorunchecked) withlocation_check_reason. A mismatch never rejects the request: the charger is stored and Joulo reviews it. See Location check. - New: the CSV delivery documents the address columns
Street,House Number,PostcodeandCity, plus an optionalHouse Number Addition. See Charge point location.
2026-10-23
- New:
managed_by_roadon each customer inGET /partner/customers. It istruewhen Road manages the customer's laadstation, through E-Flux or a portal that Road runs. Road's terms keep that data inside the ERE service, so such a row carries onlycustomer_ref,attached_monthandpartner_share_pct. The other fields are empty,sourceisself_signupandhas_chargeris absent. Your share on the customer stays. - Changed:
GET /partner/ere-positionsleaves out a customer whose laadstation Road manages.
2026-10-21
- New:
GET /partner/replacement-ordersgives one order or a page of them, with one status ladder (awaiting_paymenttocompleted) and the installer's name and phone fromscheduledon.POST /partner/replacement-orders/cancelcloses an unpaid order. On the sandbox,POST /sandbox/v1/replacement-orders/{id}/advancewalks the ladder without Mollie. See Status. - New:
POST /partner/replacement-ordersorders Joulo's replacement offer for one of your customers. The answer carries acheckout_url: a Joulo page your app opens, where the customer pays through Mollie and comes back to your app with?status=paid|cancelled|failed&order=<order_id>. One open order per customer, idempotent onexternal_ref, 30 minutes to pay. See Ordering. - New:
GET /partner/replacement-offersgives Joulo's own offer for replacing a laadstation without a MID meter, the same products and prices as joulo.nl/vervangen. With acustomer_refit names the laadstation for that customer, withsame_brandfirst and regional alternatives only inside their service area. Without one it lists the catalogue. Read-only: ordering through the API follows later. See Replacement offer.
2026-10-19
- Breaking for energy partners:
POST /partner/customersandPOST /partner/drafts/importrefuse a row from an energy partner without an EAN, with reasonmissing_eanand a count inskipped.missing_ean. Without an EAN an energy supplier no longer vouches for the customer, so they get the iDIN step. An address alone does not vouch anymore. See bank verification. - For an energy partner the upload names rows without a tenaamstelling or a
contract start date in
missing_recommended. A warning: the draft exists. POST /partner/customersandPOST /partner/drafts/importtake three optional fields per customer:account_holder_name(the tenaamstelling),supply_start_date(the start date of the energy contract on the EAN) andmove_in_date(the day the customer moved to the address).GET /partner/draftsreturns all three. A date we cannot read never rejects the row: it is named indates_ignored. See Tenaamstelling, contract start and move-in date.
2026-10-17
- Breaking, effective today: the
brandadded on 2026-10-08 is now calledlabel. On the same customer row,brand_asked_atandreplacement_offer.brandare about the laadstation, so one word had two meanings. No partner had sent abrandyet. What changes:GET /partner/brandsis nowGET /partner/labels, and answers{ "labels": [{ "label", "name" }] }.POST /partner/customersandPOST /partner/drafts/importtakelabelper row, returnlabelincreated[]and report the match inlabels.GET /partner/drafts,GET /partner/customersandGET /partner/ere-positionsreturnlabelinstead ofbrand.
POST /partner/customersandPOST /partner/drafts/importfail with HTTP 500 when Joulo cannot check thelabelvalues on the rows. Nothing is stored, so you can send the request again. Until today the rows went in without a label, every label was reported as unknown, and a resend was refused asalready_drafted.- Without an upload, a customer gets a
labelonly when their choice of energy supplier on joulo.nl links them to you. Not every label inGET /partner/labelsdoes that yet. See Labels.
2026-10-15
- An energy supplier that uploads a customer with their EAN or address vouches
for who they are. That customer never gets the iDIN step: not in your app,
not on the claim page and not in the sandbox. Until today the sandbox asked
iDIN of every new customer, so
POST /sandbox/v1/drafts/{id}/claimwithsubmit: truecould fail withsubmit_failedand reasonidin_required. For other partners nothing changes. See bank verification.
2026-10-13
- An activation that ends in
ean_conflictno longer changes the customer's account. Since 2026-10-08 it could still make your company their energy company in Joulo, so the customer appeared in yourGET /partner/ere-positionswhile their draft was onconflict. We now check the EAN before anything is written. See what comes back to your app.
2026-10-12
GET /chargersand the MCP toollist_chargersreturnaccesson OCPP chargers: the "Laden & toegang" choice the dashboard shows (no_tag,any_tagorown_tags), who chose it, and what the charger itself reported at its last reading. See Chargers.GET /chargersand the MCP toollist_chargerssay whether Joulo hears from a charger.statuskeeps its meaning (the record isactive), and its description now says so: it is not the link. New:connection_status,last_seen_at,last_seen_basis,history_paused_since,connection_help_urlandconnection_action_url, with the rules of the dashboard card.docs_urlnow appears on every charger whose brand has a manual. See Chargers.GET /sessionsreturnsmeter_start_whandmeter_stop_wh, andcurrent_sessioninGET /chargersreturnsmeter_start_wh. See Sessions.- New:
GET /registration-statusand the MCP toolget_registration_status. Per step, what is done and what is still open before Joulo can sell your ERE, in the order ofblockedinGET /ere-position. Requiresposition:read, so existing connections need no new permission. See Get where your ERE registration stands. GET /chargersand the MCP toollist_chargerstell an open session apart from energy flowing.is_chargingkeeps its meaning (a session is open). New:charging_state(charging,paused,idle,unknown),power_kwandlast_energy_at, all from the OCPP meter. On a Sunday morning only 75 of 516 open sessions had a moving meter; the rest were full cars. See Chargers.
2026-10-11
- In the dashboard the MCP connector card moved from Developer > API to its own tab, Developer > MCP. The server and the API do not change. See AI assistants (MCP).
GET /ere-positionnames why a forecast is 0 while the quarters show production.blocked.reasonwasibanornull; it now also takesregistration,mandate,eanandreview, andblocked.by_reasonlists every reason with its ERE. An account that only misses its IBAN reads exactly as before.GET /sessionsreports the live kWh of a running session, read from the same meter asGET /chargers. It said0until the session ended.GET /chargersreturnsbrandandmodelfor each charger, and the MCP toollist_chargersreturns them too. Both arenullwhen Joulo does not know them. The reference now also listsmid_eligible, which the endpoint already returned. See Chargers.
2026-10-10
- AI assistants can read the personal API through the Joulo MCP server at
https://joulo.nl/mcp. It offers five read-only tools on top ofGET /me,/chargers,/sessions,/energyand/ere-position. See AI assistants (MCP). - The OAuth2 server accepts dynamic client registration and public clients
without a
client_secret. Clients that Joulo created for you work as before. See OAuth2.
2026-10-09
GET /partner/ere-positionsandGET /partner/customerssay why a connection yields no ERE.mid_statusismid,no_mid,unknownornone. Withno_mid,replacement_offernames the laadstation with a MID meter from your own store that fits this customer, with its price and product page, so your app can show the customer what to do next. Both fields are new and optional to read. See ERE positions.
2026-10-08
- A partner with several brands can send a
brandper customer. New:GET /partner/brandslists your brands.POST /partner/customersandPOST /partner/drafts/importaccept an optionalbrandand report the match inbrands.GET /partner/drafts,GET /partner/customersandGET /partner/ere-positionsreturnbrand. The brand is display only: the fee, the payout and the attribution follow the partner. See Labels. - A customer who is already with Joulo can activate from your app. With
send_invite: false,POST /partner/customersandPOST /partner/drafts/importno longer refuse an address whose Joulo account holds data. The row becomes a draft, and the answer is the same as for a new address. In your app the customer signs in with their own account and confirms. Withsend_invite: truesuch an address still getsexisting_user. See the app flow. - Activating the draft of an energy supplier makes that supplier the
customer's energy company in Joulo, also when another one was set. The
customer then appears in your
GET /partner/ere-positionswith yourexternal_ref. - An energy supplier sees a customer only while it is that customer's energy
company in Joulo. A customer who switches supplier leaves the old supplier's
GET /partner/ere-positionsandGET /partner/customers, also when they first came in through that supplier. Until today such a customer stayed in both. Installers and other partners keep their customers. See what a switch of energy supplier changes. - A customer who activated one of your drafts is in your
GET /partner/customers, also when another partner brought them in first. Until today such a customer was missing from the list. POST /partner/customersandPOST /partner/drafts/importno longer refuse a row for its EAN.conflictno longer comes back, andskipped.conflictis always0. Only the activation checks the EAN: when another customer holds it, the app flow ends inean_conflictand the draft moves toconflict. Another partner's draft of the same customer never blocks an activation.
2026-10-05
POST /partner/customersandPOST /partner/drafts/importrefuse fewer rows withexisting_user. An existing Joulo account without a charger, charging sessions, a signed authorisation or a submitted registration no longer blocks the row. When the customer opens your auth-link, we replace that empty account and the flow continues. Nothing changes in the request or the response. See the app flow.POST /partner/drafts/withdrawnow works with a partner API key. It deletes a draft that is notactiveyet, so the claim link and our reminders stop. The address is free again for a new upload. Errors carry acode:draft_id_required,draft_not_foundordraft_active. See Withdrawing a draft.
2026-10-01
GET /partner/ere-positions: a customer can turn off sharing with the energy supplier they picked in their account. From then on the row drops out of that supplier's feed, andcountdrops with it. The row stays in the feed of a partner the customer signed up through, unless that is the same supplier. Delete a missing EAN from your own copy as well. The response shape does not change.GET /partner/ere-positions: each row now carriescustomer_refandsource.customer_refis the same pseudonymous reference as inGET /partner/customers, and tells two customers on one EAN apart.sourcehas a new value,supplier_choice, for a customer linked to you only through their choice of energy supplier.GET /partner/ere-positionsno longer returns a customer who made themselves invisible to partners (a GDPR objection). Before, the row stayed withexternal_refset tonull.countdrops by the same number. See Linking a row to your own customer.
2026-09-24
GET /partner/ere-positionsanswers 403 to a partner in the installer work model (installer, garage, distributeur). An installer reads its customers throughGET /partner/customers. Energy partners and platforms see no change.
2026-09-23
GET /v1/accounts: each connection now carriesstatus,activeorarchived. After the customer signs, we re-check anunverifiedconnection about once a week. A correction throughPOST /v1/connections:updatenow keeps the check result it returned.- The API reference now describes the Partner API, the CPO API and the sandbox helpers. It comes from the same OpenAPI description that CI checks.
- New sandbox helper:
POST /sandbox/v1/drafts/{id}/claimclaims a draft as the customer, and submits the registration if you ask. See test values and helpers. - A repeat
POST /v1/accountsnow returns the account's currentmandate_status. Before, it returnedpendingeven after the customer signed.