Skip to content

Quick start

  1. Create a key under Settings › API keys (Dutch app: Instellingen › API-sleutels). catalogue:read is enough to start; the write examples need catalogue:write and sales:write.
  2. Put it in an environment variable:
Terminal window
export EUROPLAYBOOK_API_KEY='ep_1a2b3c4d_...'
export API_BASE='https://api.europlaybook.com/v1'
Terminal window
curl -s "$API_BASE/account" \
-H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"

Lists use a cursor. Keep calling with next_cursor until it is null.

Terminal window
curl -s "$API_BASE/products?limit=100" \
-H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"
# then: ...&cursor=<next_cursor>
Terminal window
curl -s "$API_BASE/products?sku=DG-HOSE-25" -H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"
curl -s "$API_BASE/products/<id>/packaging" -H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"

The response is a tree: layers[] > lines[] > item > materials[], plus totals_by_material and confirmation. Weights are integer milligrams. Lines the product inherits from its group have inherited: true and group_id; every line says where it came from (source, source_ref).

Each figure of a period can be traced back. Take a key from declared.lines of the period totals and ask where it comes from:

Terminal window
curl -s "$API_BASE/periods/<period_id>/totals" -H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"
curl -s "$API_BASE/periods/<period_id>/totals/<key>/explain" -H "Authorization: Bearer $EUROPLAYBOOK_API_KEY"

You get the ledger entries behind the line, the products (largest share first) with the packaging lines used and their evidence count, and the units sold per month and channel.

Up to 1000 lines per request. external_id is your own id for the line; sending it again does not count it twice.

Terminal window
curl -s -X POST "$API_BASE/sales" \
-H "Authorization: Bearer $EUROPLAYBOOK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2026-10-batch-1" \
-d '{"lines":[{"external_id":"order-1001-1","sku":"DG-HOSE-25","sold_on":"2026-10-03",
"quantity":2,"ship_from_country":"NL","ship_to_country":"BE","channel":"webshop"}]}'

The answer counts what happened to the lines:

{ "created": 1, "updated": 0, "unchanged": 0, "held": [], "unknown_skus": [] }
Field Meaning
created New lines
updated Lines sent before (same external_id) whose values changed
unchanged Lines sent before with the same values
held external_ids not stored because a locked or filed period covers them; reopen the period in the app first
unknown_skus SKUs without a product. The lines are stored; create or map the product and they count

Open periods that overlap the dates are recalculated in the background. Never send personal data of consumers. A country code is all EuroPlaybook needs.

PUT with the SKU in the path creates the product (201) or updates the fields you send (200). title is required. This writes directly; it does not touch the product’s packaging or its confirmation.

Terminal window
curl -s -X PUT "$API_BASE/products/by-sku/DG-SPRINK-01" \
-H "Authorization: Bearer $EUROPLAYBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Garden sprinkler","net_weight_mg":350000,"country_of_origin":"NL","is_electrical":false}'

Regime profiles hold product data for other EPR regimes, such as epr.weee. A PUT stores a proposal (state: proposed, source: api); a person confirms it in the app. data must match the regime’s schema (422 otherwise). Send valid_from to start a new version on that day; leave it out to change the version valid today.

Terminal window
curl -s -X PUT "$API_BASE/products/<id>/profiles/epr.weee" \
-H "Authorization: Bearer $EUROPLAYBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"data":{"in_scope":true,"category":5,"weight_mg":420000,"has_battery":true,"battery_weight_mg":45000}}'

epr.weee data: in_scope, category (1-6), weight_mg, has_battery, battery_weight_mg, notes. epr.textiles: in_scope, weight_mg, notes. Read them back with GET /products/{id}/profiles.

Next: the API reference lists every endpoint and field.