Propose packaging lines
const url = 'https://api.europlaybook.com/v1/products/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/packaging/proposals';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"lines":[{"item_id":"0199f5a2-7c1e-7b4a-9d0e-3f6c2a1b8e44","layer":"sales","quantity":"1","valid_from":"2026-01-01"},{"layer":"sales","new_item":{"materials":[{"mass_mg":8000,"material":"paper"}],"name":"Kraft pouch"}}]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.europlaybook.com/v1/products/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/packaging/proposals \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "lines": [ { "item_id": "0199f5a2-7c1e-7b4a-9d0e-3f6c2a1b8e44", "layer": "sales", "quantity": "1", "valid_from": "2026-01-01" }, { "layer": "sales", "new_item": { "materials": [ { "mass_mg": 8000, "material": "paper" } ], "name": "Kraft pouch" } } ] }'Adds lines with state proposed. Like any packaging change this clears the product’s
confirmation (gate 1) and opens a “confirm packaging” task: a person confirms in the portal.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”Proposed packaging lines. They are stored with state proposed; the product’s packaging
confirmation (gate 1) is cleared and a person confirms in the portal. The API never confirms.
object
One proposed line. Send item_id (a part from the library, see /packaging-items) or new_item.
object
A new packaging part for this product only, created together with the proposed line.
object
Material breakdown of one part.
object
Material code (see /reference/materials).
Mass of this material in ONE part, milligrams.
Responses
Section titled “Responses”Created
object
The lines this call created (or found unchanged).
A product’s packaging as a tree: layers > lines > item > materials, plus the totals per material
for one day. The product’s own lines and the lines it inherits from its group (per layer: own lines
valid on a day replace the group’s); each line has source, source_ref, inherited, group_id.
object
The day the totals are for (query parameter on, default today).
Gate 1 passed (see ProductOut.packaging_confirmed).
Gate 1 with the packaging fingerprint.
object
Sales (primary), grouped (secondary) or transport (tertiary).
One packaging line: quantity parts of item per sales unit, valid over a date range.
object
Proposed = not yet checked by a person; confirmed = part of a gate-1 confirmation.
Parts per sales unit (may be a fraction, e.g. 1 film per 1440).
Ends up with households (counts as household packaging).
Packaging mass per sales unit for this line (item mass x quantity).
Counted in totals_by_material: valid on on and not limited to a channel/fulfilment.
Where the line came from (provenance).
Which record of that source, e.g. api:token:<prefix>.
The line is the product group’s: the product has no own line on that layer.
object
Name of the packaging part.
Your code for the part (unique per account when set).
Usual role: sales, grouped, transport, shipping or filler.
Usually ends up with households (vs. businesses).
Can be separated from the other parts by hand.
Material breakdown of ONE part.
object
Material code from the knowledge pack (see /reference/materials).
Mass in milligrams.
Sum of the materials, milligrams.
Mass per sales unit of this layer’s lines that count in the totals.
Packaging per sales unit by material on on (lines with in_totals), heaviest first.
object
Material code from the knowledge pack (see /reference/materials).
Mass in milligrams.
Sum of totals_by_material.
Automatic plausibility checks on today’s lines.
object
Example
{ "packaging": { "product_id": "0199f5a2-7c1e-7b4a-9d0e-3f6c2a1b8e44", "sku": "TEA-001", "confirmation": { "state": "none" }, "layers": [ { "layer": "sales", "lines": [ { "id": "0199f5a2-7c1e-7b4a-9d0e-3f6c2a1b8e44", "state": "proposed", "quantity": "1.0000", "source": "manual", "source_ref": "", "inherited": false, "item": { "id": "0199f5a2-7c1e-7b4a-9d0e-3f6c2a1b8e44", "name": "Folding box S", "code": "BOX-S", "rigidity": "rigid", "materials": [ { "material": "paper", "mass_mg": 12000 } ], "total_mass_mg": 12500 } } ] } ], "totals_by_material": [ { "material": "paper", "mass_mg": 12000 } ], "total_mass_mg": 14500, "findings": [] }}Bad Request
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}Unauthorized
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}Forbidden
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}Not Found
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}Conflict
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}Unprocessable Content
object
What went wrong, in English, for people and logs.
Stable machine-readable error code; translate and branch on this.
Per-field problems (pydantic format: loc, msg, type).
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }, "errors": []}Too Many Requests
object
Example
{ "detail": "This API key lacks the scope catalogue:write", "code": "insufficient_scope", "params": { "required_scope": "catalogue:write" }}