JouloDocs

Sandbox test values and helpers

Drive a test customer through every state on the sandbox, from EAN check to ERE position, without waiting for Joulo.

The sandbox (https://api-staging.joulo.nl) runs the same code as production, on test data. A real customer waits for a review by Joulo, needs a charger that syncs, and receives mail. On the sandbox you drive those steps yourself: test values pick an outcome, and helper endpoints move a customer to the next state.

The helpers work with your sandbox credentials only: a Partner API key (jpk_test_) or a CPO client. They reach your own customers only. Production answers every /sandbox path with 404.

Test values

The sandbox never calls the Dutch EAN register. It answers from the input, so each outcome can be reproduced on purpose.

EAN, by its last four digits:

EAN ends inean_validation_statusWhy
0002unverifiedThe register does not know the address. Typical for a new build.
0003mismatchedThe address holds a different EAN.
0005mismatchedThe EAN exists at another address. The customer may explain.
0009unavailableThe register is down. A customer cannot submit a registration until it answers.
anything elsematchedThe EAN sits at exactly this address.

House number, for address lookups without an EAN:

House numberResult
404No leverpunt on this address.
300Two leverpunten, additions A and B: the customer picks one.
anything elseOne leverpunt, with a sandbox EAN that ends in 0001.

Email address of the customer:

AddressReview outcome
contains +afgekeurd before the @afgekeurd
anything elsegoedgekeurd

A submitted registration is reviewed automatically two minutes after submission. Use the review helper to decide sooner or to change the outcome.

To test ean_in_use, register the same EAN for a second customer.

Helpers

Base URL: https://api-staging.joulo.nl/functions/v1/api. A draft {id} is a draft id or your external_ref from GET /partner/drafts. A customer {id} is a customer_ref from GET /partner/customers, or an account id from the CPO API or the claim helper.

Method and pathDoes
GET /sandbox/v1Lists the helpers and the test values.
GET /sandbox/v1/mail?to=&limit=Mail your customers would have received, newest first, with the links in it.
POST /sandbox/v1/drafts/{id}/claimClaims a draft as the customer, and submits the registration if you ask.
POST /sandbox/v1/customers/{id}/reviewApproves or rejects a submitted registration.
POST /sandbox/v1/customers/{id}/chargersConnects a virtual charger and collects its sessions.
POST /sandbox/v1/customers/{id}/syncCollects the virtual charger's newest sessions now.
POST /sandbox/v1/positions/refreshRecomputes ERE positions now instead of within 15 minutes.
POST /sandbox/v1/fixturesCreates ready-made customers, one in each state.
POST /sandbox/v1/resetDeletes all your sandbox customers and drafts.

Claim a draft as the customer

On production the customer opens the claim link, signs the machtiging and submits the registration. This helper does those steps for you, through the same code the claim page and the registration form use:

curl -X POST "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/drafts/CRM-42/claim" \
  -H "Authorization: Bearer jpk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"submit": true}'
{
  "ok": true,
  "draft_id": "0d2b7a1e-…",
  "external_ref": "CRM-42",
  "account_id": "4c1f…",
  "draft_status": "active",
  "registration_status": "ingediend",
  "steps": { "claim": "ok", "activate": "ok", "submit": "ok" },
  "next": "The automatic review decides in about two minutes. …"
}

Without submit the helper stops after the machtiging, like a customer who has not filled in the registration yet. With submit: true it also connects a virtual charger and submits the registration from the data you uploaded.

FieldDefaultMeaning
submitfalseAlso connect a virtual charger and submit the registration.
ibanthe test IBAN NL91ABNA0417164300 with submit, else noneStored as the customer would enter it. ERE is allocatable only with an IBAN, so send null to test a customer without one.
eanthe uploaded EAN, else the sandbox EAN for the addressA test value here picks the EAN outcome.
charger{"mid": true, "since": "2026-01-01"}The virtual charger, with the fields of the charger helper.
phone, streeta test number and streetFields the upload does not carry.

A missing name, postcode, house number or city falls back to a test value. submit works for particulier drafts. A business registration needs a KvK extract, so finish it on staging.joulo.nl.

The helper never logs into an account you did not create, on the sandbox either. It answers 409 existing_account when the draft's email already belongs to an account, and 409 claimed_by_customer when someone claimed the draft through its link.

Read the mail a customer received

The sandbox sends no mail to your test addresses. It keeps every mail instead, so you can open the claim link or the login link yourself.

curl "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/mail?to=test%[email protected]" \
  -H "Authorization: Bearer jpk_test_..."
{
  "mail": [
    {
      "captured_at": "2026-09-23T12:04:11Z",
      "to": "[email protected]",
      "subject": "Je laadstation levert geld op",
      "template": "partner-draft-invite",
      "links": ["https://staging.joulo.nl/claim/3f0c…"]
    }
  ]
}

Review a registration

curl -X POST "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/customers/1a2b3c4d/review" \
  -H "Authorization: Bearer jpk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"outcome": "goedgekeurd"}'

The customer must have submitted the registration first. Otherwise the helper answers 409 not_submitted.

Connect a virtual charger

curl -X POST "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/customers/1a2b3c4d/chargers" \
  -H "Authorization: Bearer jpk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"mid": true, "kwh_per_session": 12, "sessions_per_week": 4, "since": "2026-01-01"}'
FieldDefaultMeaning
midtruefalse connects a charger without a MID meter. Its sessions never count toward ERE.
kwh_per_session12Average energy per session.
sessions_per_week4Average sessions per week, 0 to 7.
power_kw11Charging power. Sets how long a session lasts.
since2026-01-01First day with sessions.

The charger's sessions are generated the same way every time, and they enter through the same pipeline as a real charger's. New sessions appear every 15 minutes, or at once with the sync helper.

See ERE positions

A session counts once the registration is approved and three days have passed since the session ended. Refresh the positions, then read them as usual:

curl -X POST "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/positions/refresh" \
  -H "Authorization: Bearer jpk_test_..."
curl "https://api-staging.joulo.nl/functions/v1/api/partner/ere-positions?year=2026" \
  -H "Authorization: Bearer jpk_test_..."

A virtual charger with sessions since January gives a customer ERE right away. Pick a recent since date to test a customer whose ERE is still in the three-day settle buffer.

Get ready-made customers

One call gives you a customer in every state your integration has to handle, without a claim or a review:

curl -X POST "https://api-staging.joulo.nl/functions/v1/api/sandbox/v1/fixtures" \
  -H "Authorization: Bearer jpk_test_..."
StateThe customer
conceptAttributed to you, nothing submitted yet.
approved_with_ereApproved, MID charger with sessions since January, ERE to sell.
rejectedRejected at review.
mismatched_eanApproved, but the EAN check found another EAN on the address.
non_mid_chargerApproved, charger without a MID meter: sessions, no ERE.
recent_chargerApproved, MID charger since two days ago: ERE still in the settle buffer.

Send {"states": ["rejected", "mismatched_ean"]} to get only some of them. Each fixture has a confirmed login on an example.com address that never receives mail. It appears in GET /partner/customers and GET /partner/ere-positions as a customer you uploaded, so you see its name and status. Its external_ref names the state, such as FIXTURE-APPROVED-WITH-ERE.

Start over

POST /sandbox/v1/reset deletes every customer attributed to you on the sandbox, and every draft you uploaded. Your key keeps working.