JouloDocs

ERE positions

GET /partner/ere-positions • per-EAN ERE position for your attributed customers, in bulk

GET /partner/ere-positions returns the ERE position per connection (EAN) for every customer attributed to you, for one compliance year. It holds registered and sellable ERE, the expected net payout, and a per-quarter breakdown. Use it to reconcile positions per connection in bulk.

The connection (EAN) is the key. Every attributed customer with an EAN on their profile gets a row. That can happen during onboarding, before the registration is submitted. A customer without an EAN is not here yet. Find them in GET /partner/customers, or in GET /partner/drafts before they claim.

Attributed covers one more group than GET /partner/customers does. An energy supplier also gets a row for every customer who picked it as their supplier in their Joulo account. A customer linked to you only that way has no row in GET /partner/customers, so an EAN here can lack a matching customer there. Such a row has source supplier_choice.

An energy supplier sees a customer only while it is that customer's energy company in Joulo. That holds for every route the customer came in by: your page, your upload or your app. A customer who switches to another supplier drops out of your feed and out of GET /partner/customers, and appears in the feed of the new supplier. See what a switch of energy supplier changes.

The customer can also turn off sharing with their supplier in their Joulo account. Their row then drops out of that supplier's feed. Delete a missing EAN from your own copy in both cases.

A customer who made themselves invisible to partners (a GDPR objection) has no row here. Their EAN would identify them to you, so we leave the whole row out.

A row does not mean ERE yet. A new row starts empty: every amount is 0, quarters is [] and computed_at is null until the first recompute (see freshness). Read ere_eligible to see whether the customer has built up ERE.

Request

curl "https://api.joulo.nl/functions/v1/api/partner/ere-positions?year=2026&limit=200&offset=0" \
  -H "Authorization: Bearer jpk_live_..."
Query paramRequiredNotes
yearnoCompliance year. Default 2026.
limitnoPage size, 1–500. Default 200.
offsetnoPage offset. Default 0.

Response

{
  "positions": [
    {
      "ean": "871685920000123456",
      "customer_ref": "3f9a1c07",
      "external_ref": "KLANT-8842",
      "source": "partner_upload",
      "registration_status": "goedgekeurd",
      "ean_validation_status": "matched",
      "ere_eligible": true,
      "mid_status": "mid",
      "replacement_offer": null,
      "compliance_year": 2026,
      "registered_ere": 234.354,
      "allocatable_ere": 227.6865,
      "pending_ere": 6.6675,
      "expected_net_eur": 319.15,
      "ytd_expected_net_eur": 251.4,
      "realized_net_eur": 214.68,
      "quarters": [
        {
          "quarter": "2026 Q2",
          "registered_ere": 177.4433,
          "sold_ere": 177.4433,
          "unsold_ere": 0,
          "price_per_ere": 0.485,
          "realized_net_eur": 68.85,
          "net_eur_by_status": { "paid": 68.85, "payable": 0, "reserved": 0 },
          "final": true
        },
        {
          "quarter": "2026 Q3",
          "registered_ere": 50.2431,
          "sold_ere": 22.1,
          "unsold_ere": 28.1431,
          "price_per_ere": 0.4712,
          "realized_net_eur": 8.33,
          "net_eur_by_status": { "paid": 0, "payable": 0, "reserved": 8.33 },
          "final": false
        }
      ],
      "computed_at": "2026-07-21T10:00:00Z"
    }
  ],
  "limit": 200,
  "offset": 0,
  "count": 250,
  "compliance_year": 2026
}
FieldMeaning
eanThe connection this position belongs to: the EAN on the customer's account.
customer_refPseudonymous reference, stable per customer and partner. The same value as customer_ref in GET /partner/customers. It tells two customers on one EAN apart. See linking a row to your customer.
external_refYour own customer reference, as supplied on upload. null when you did not supply one, or when the customer did not come in through your upload. See Upload customers.
labelYour label for this customer, the same value as in GET /partner/customers. null when the customer has no label of yours. See Labels.
sourceHow the customer came to you. partner_upload, partner_invite and self_signup mean the same as in GET /partner/customers. supplier_choice: linked only because the customer picked you as their energy supplier.
registration_statusRegistration lifecycle: concept → ingediend → in_review → goedgekeurd (or afgekeurd).
ean_validation_statusEAN validation against the Dutch EAN register: matched, unverified (the register does not know the address yet, typical for new builds), mismatched (the register holds a different EAN at this address) or unavailable (the check could not run). See below.
ere_eligibletrue when eligible ERE has been produced (sellable + in the settle buffer).
mid_statusWhy there is or is not any ERE: mid (a laadstation with a MID meter), no_mid (laadstations, none with a MID meter), unknown (not determined yet) or none (no laadstation linked). See below.
replacement_offerWith no_mid: the laadstation with a MID meter from your own store that fits this customer. null otherwise.
registered_ereAll eligible ERE this year: sellable plus what is still inside the 3-day settle buffer.
allocatable_ereERE that has cleared the settle buffer and is available to sell.
pending_ereERE inside the 3-day settle buffer • rolls into allocatable_ere over the next days.
expected_net_eurExpected net payout to the customer for the full year (market-based, indicative).
ytd_expected_net_eurEarned so far this year: realised, plus every ERE already charged but not yet sold, valued at market. Includes the 3-day settle buffer, so this covers all eligible kWh charged this year.
realized_net_eurNet payout the customer has actually earned this year: every ERE that is sold, at the real trade price.
quarters[]Per quarter: production, what was sold from it, and the money it produced. See below.
computed_atWhen this position was last recomputed (see freshness below). null until the first recompute.
countTotal attributed connections, for pagination.

All amounts are the customer's net payout, never Joulo's gross. realized_net_eur is money the customer has actually earned, at the real trade price; expected_net_eur is a market-based forecast and never a guarantee. Only connections attributed to you are returned.

Realised euros per quarter

Each quarter reports what it produced and what that produced in money.

FieldMeaning
registered_ereEligible ERE produced in that quarter, including what is still in the 3-day settle buffer. The quarters therefore add up to the top-level registered_ere.
sold_ereOf that, how much is sold.
unsold_ereThe remainder, still waiting for a sale.
price_per_ereWeighted gross trade price of the sold part. null while nothing is sold. Every sale is public in the sale log.
realized_net_eurNet to the customer over sold_ere: paid, payable and reserved together.
net_eur_by_statusThe same amount split into paid, payable and reserved.
finaltrue when the quarter has ended and nothing is unsold. The quarter is then definitive.

A quarter becomes definitive when its ERE is sold, not when the calendar turns. The sale sets the price and therefore the payout. We sell in tranches, so a closed quarter keeps filling up for a while after it ends. Read final rather than comparing the quarter to today's date.

A reserved allocation is not a guess. The price is fixed the moment the trade is agreed. Only the commission can still change at settle. By the LEAST(fee at reserve, fee at settle) rule it can only drop, in the customer's favour. That is why reserved counts in realized_net_eur in full, exactly as the customer's own Opbrengsten tab counts it.

These are the same figures and the same three buckets the customer sees in the Joulo dashboard. If your app and our dashboard ever disagree, that is a bug on our side. Report it.

final also stays false when the customer produced ERE that Joulo cannot sell, for example while an IBAN is missing. That is the honest answer: nothing is realised on that quarter yet.

A quarter that has just ended also stays false while its last sessions are in the 3-day settle buffer. Those kWh still belong to that quarter, and a meter reading can change until the buffer clears.

MID status and the replacement offer

Only a laadstation with a MID meter counts for ERE. A customer with mid_status = no_mid has linked a laadstation, but none of theirs has one, so the position stays at zero until the laadstation is replaced. Sessions count from the moment the MID meter is there. Nothing from before counts later.

For that customer replacement_offer names a laadstation from your own store. Joulo picks a model of the same brand as the customer's current laadstation when your store has one, else your first model with a MID meter. The products are the ones Joulo lists for you on your co-branded page. Ask Joulo to add or change one.

"mid_status": "no_mid",
"replacement_offer": {
  "name": "Zaptec Go 2",
  "brand": "Zaptec",
  "price_eur": 899,
  "list_price_eur": 929,
  "url": "https://example.com/store/zaptec-go-2",
  "image_url": null,
  "same_brand": true
}
FieldMeaning
nameProduct name as it appears in your store.
brandBrand of the offered laadstation.
price_eurWhat the customer pays today, in euros including VAT: the sale price when there is one, else the list price.
list_price_eurList price in euros including VAT.
urlProduct page in your store. Send the customer there.
image_urlProduct image, when Joulo has one.
same_brandtrue when the offered laadstation has the same brand as the customer's current one.

The customer's own brand and model are not in the feed. GET /partner/customers names them only for customers you uploaded.

Per connection, not per person

A position belongs to a connection, because the authorization to register with the NEa is bound to one party per EAN. Two people at the same address never build separate positions on one EAN at the same time. There is exactly one authorization holder per period.

Successive occupants do happen. What was registered under the previous occupant's authorization stays on their account and is paid out to them. The new occupant builds up from their own authorization date. In that case the same ean appears on two rows with a different customer_ref: one per customer, each with its own build-up. Rows with the same ean are ordered by customer_ref.

Linking a row to your own customer

Only a customer you uploaded carries your external_ref. For every other row, link it to your own customer yourself:

  1. Match the ean to the connection in your own records. Do not match on email address: a customer can use another address at Joulo than with you.
  2. Store the customer_ref with your customer. From then on, read the row by customer_ref, not by ean.

To get your external_ref on such a customer, let them activate in your app. Upload them with send_invite: false and open the auth-link, as described in the app flow. The customer signs in with their own Joulo account and confirms. The row then carries your external_ref and source: partner_upload, and keeps its customer_ref. POST /partner/customers never changes an existing account without the customer's own login.

With send_invite: true, an address that already has a Joulo account with data is rejected with existing_user, because our invite mail asks the reader to create an account.

Two rows with the same ean and no external_ref cannot be told apart by the EAN alone. Do not link either one automatically. Ask the customer, or contact us with both customer_ref values.

What a switch of energy supplier changes

The ERE position hangs on the connection and on the authorization the customer gave Joulo, not on who supplies the electricity. A customer who switches supplier keeps the same position for the compliance year. That includes kWh from before the switch. Joulo registers retroactively from 1 January 2026, as far back as the charger connection can deliver historical sessions.

What changes is who sees the row:

  • The new supplier gets the row on its next request, with the full position, the kWh from before the switch included.
  • The old supplier loses the row on its next request. The customer also leaves its GET /partner/customers. That holds when the customer first came in through the old supplier too.
  • Other partners, such as the installer, keep the row.

A switch in the customer's Joulo account and an activation in the app of the new supplier have the same effect.

One limit: if another registration service provider held the authorization on that EAN earlier and already registered kWh, those periods cannot be registered again. Those ERE stay with that party and never appear here.

EAN validation status

mismatched means the Dutch EAN register knows the address, but holds a different EAN there. It happens in three ways:

  • The customer submitted with a motivation. The EAN is registered at this postcode and house number, but the address label differs (a missing addition, another street spelling). A Joulo admin reviews it before anything reaches the NEa.
  • The registration went in as unverified (new build). Our weekly check found the address later, with a different EAN.
  • The address changed after submission, and the recheck found a different EAN.

The customer cannot fix this alone: after submission the EAN and address are read-only. Advise them to send us a message from their Joulo dashboard. We check the EAN with them and correct it.

unverified needs no action from the customer. We recheck it every week.

Freshness and polling

Positions are recomputed roughly every 15 minutes; computed_at tells you how fresh each row is. They move slowly (a 3-day settle buffer plus the daily sync), so polling a few times per day is plenty. There is no push webhook.

We recompute positions only for partners with an active API key. After you mint your first key, rows can stay empty until the next recompute.

Access

This endpoint is on the API-key allowlist, so your jpk_live_ key can read it directly. It only ever returns connections attributed to your own account.