LCA Provider Integration Guide
Step-by-step walkthrough for Life Cycle Assessment (LCA) providers who need to pull product data, supply chain structure, company energy sources, and material composition from the Retraced Public API.
Setup
BASE_URL="https://publicapi.retraced.com/api/v2"
# API key provided by the brand you are integrating with
API_KEY="your-api-key"
All examples use curl. The API key is passed via the companyapikey header.
Important: If your API key contains
$characters, use single quotes around its value to prevent the shell from interpreting it as a variable:-H 'companyapikey: $2b$10$...' # correct — single quotes -H "companyapikey: $2b$10$..." # wrong — shell expands $2b to empty string → 401
All responses use the standard envelope: { "metadata": { "success": true }, "data": ... }. Errors return metadata.success: false plus a machine-readable code field.
Overview
The typical LCA data collection workflow involves four steps:
- Fetch the product hierarchy — styles, variants, and SKUs
- Fetch the supply chain — which facilities produce the product and at which tier
- Fetch energy source data — ESG section 2.1.6.1 for each supplier company
- Fetch material composition — material headers and material lines for the product
The example below uses a single product: Summer Dress 2024 (style style_01KMZMMMW8JA3S1RVX1PS8E19S), one variant in Blue (variant_01KN6YZNVKNBN1TJ4MR9T7FFD0), and one SKU in size S (sku_01KN6Z1JB710ANAN120JH5BBB0).
Step 1 — Fetch the product hierarchy
1a. List all styles
Retrieve the top-level product catalogue. Use nameOrCode to search for a specific product.
curl "$BASE_URL/styles?level=style&page=1&limit=50" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 50, "total": 7, "totalPages": 1 }
},
"data": [
{
"id": "style_01KMZMMMW8JA3S1RVX1PS8E19S",
"forCompanyId": "G3JITT4AM9L",
"name": "Summer Dress 2024",
"codes": [{ "codeId": "ERP_ID", "codeValue": "DRS-2024-001" }],
"description": "Lightweight summer dress in organic cotton",
"gender": "female",
"styleLevelId": "APPAREL_END_CONSUMER_FINISHED_GOODS",
"styleTypeId": "Y0RL9LGNUWOL9RXB07",
"brands": [],
"departments": [],
"seasons": [],
"suppliers": [],
"mainSupplier": null,
"isComponent": false,
"isArchived": false,
"weight": null,
"createdAt": "2026-03-30T15:08:48.904Z",
"updatedAt": "2026-03-30T15:08:49.545Z"
}
]
}
STYLE_ID="style_01KMZMMMW8JA3S1RVX1PS8E19S"
Weight for functional units:
weightis{ "value": number, "unit": "GRAM" | "KILOGRAM" | ... }ornullwhen the brand hasn't entered it. Variant and SKU responses additionally exposeisWeightAvailable, and inherit the parent's weight when their own is not set — if you need a mass for your functional unit and the SKU returnsnull, check the parent style.
1b. List variants for the style
curl "$BASE_URL/styles?level=variant&styleId=$STYLE_ID&page=1&limit=50" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
},
"data": [
{
"id": "variant_01KN6YZNVKNBN1TJ4MR9T7FFD0",
"forCompanyId": "G3JITT4AM9L",
"name": "Summer Dress 2024 — Blue",
"codes": [{ "codeId": "ERP_ID", "codeValue": "DRS-2024-001-BLU" }],
"description": "Lightweight summer dress in organic cotton",
"gender": "female",
"styleLevelId": "APPAREL_END_CONSUMER_FINISHED_GOODS",
"styleTypeId": "Y0RL9LGNUWOL9RXB07",
"suppliers": [],
"mainSupplier": null,
"isComponent": false,
"isArchived": false,
"weight": null,
"isWeightAvailable": false,
"createdAt": "2026-04-02T11:24:17.139Z",
"updatedAt": "2026-04-02T11:24:39.088Z"
}
]
}
VARIANT_ID="variant_01KN6YZNVKNBN1TJ4MR9T7FFD0"
1c. List SKUs for the variant
curl "$BASE_URL/styles?level=sku&variantId=$VARIANT_ID&page=1&limit=50" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 50, "total": 7, "totalPages": 1 }
},
"data": [
{
"id": "sku_01KN6Z1JB710ANAN120JH5BBB0",
"forCompanyId": "G3JITT4AM9L",
"name": "Summer Dress 2024 — Blue — S",
"codes": [{ "codeId": "EAN_GTIN_13", "codeValue": "4006381333931" }],
"description": "Lightweight summer dress in organic cotton",
"gender": "female",
"styleLevelId": "APPAREL_END_CONSUMER_FINISHED_GOODS",
"styleTypeId": "Y0RL9LGNUWOL9RXB07",
"suppliers": [],
"mainSupplier": null,
"isComponent": false,
"isArchived": false,
"weight": null,
"isWeightAvailable": false,
"createdAt": "2026-04-02T11:25:19.079Z",
"updatedAt": "2026-04-02T11:25:52.639Z"
}
]
}
Note: Supply chain and material data can be attached at the style, variant, or SKU level — and child products inherit from their parent when they have nothing of their own (see the notes in Steps 2 and 4). In this example we continue at the style level using
STYLE_ID; substituteVARIANT_IDorSKU_IDto work at a finer granularity.
Step 2 — Fetch the supply chain
Retrieve the supplier network for the product. Each node in the response represents a facility, grouped by production process and tier.
The endpoint accepts a style, variant, or SKU ID. If the product you query has no supply chain of its own, the platform automatically falls back to the closest ancestor's active supply chain — so querying a SKU returns the style's chain when the brand mapped at style level.
curl "$BASE_URL/supply-chains/$STYLE_ID" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": { "success": true },
"data": {
"productId": "style_01KMZMMMW8JA3S1RVX1PS8E19S",
"productName": "Summer Dress 2024",
"nodesByProductionProcesses": [
{
"productionProcessId": "MANUFACTURING",
"productionProcessName": "Manufacturing",
"tier": "T2",
"nodes": [
{
"tier": "T2",
"companyId": "G3JITT4AM9L",
"companyName": "Developers' CMT & Fabric",
"country": "DK",
"coordinates": { "latitude": 55.681986, "longitude": 12.600743 },
"address": {
"line1": "Ekvipagemestervej 10",
"line2": null,
"city": "København",
"zipCode": "1438",
"country": "DK"
},
"facilityProcesses": ["Cut make trim (CMT)"],
"productionProcess": "Manufacturing"
}
]
},
{
"productionProcessId": "SOURCING_AND_IMPORT",
"productionProcessName": "Sourcing and import",
"tier": "T1",
"nodes": [
{
"tier": "T1",
"companyId": "PZ86G3I3SXB",
"companyName": "Creative Sourcing Co. Ltd.",
"country": "CN",
"coordinates": { "latitude": 31.322372, "longitude": 120.722366 },
"address": {
"line1": "Jiangsu",
"line2": null,
"city": null,
"zipCode": null,
"country": "CN"
},
"facilityProcesses": ["Sourcing agency"],
"productionProcess": "Sourcing and import"
}
]
}
]
}
}
Reading the response:
tier—T1is the tier closest to the finished product (e.g. final assembly / sourcing), with higher numbers further upstream toward raw materials.coordinatesandaddressarenullwhen the brand hasn't geo-located the facility or hasn't entered a full address.facilityProcesses— the facility-level process names (empty array if none recorded).- An empty
nodesByProductionProcessesarray is a valid 200 response — it means the product (and its ancestors) have no active mapped supply chain. A404 not_found("Style not found") means the product ID itself doesn't exist.
Collect the companyId values for the next step:
COMPANY_IDS=("G3JITT4AM9L" "PZ86G3I3SXB")
Step 3 — Fetch energy source data (ESG section 2.1.6.1)
For each supplier company from Step 2, retrieve their declared energy sources using the templateId=2.1.6.1 filter. This returns only data points belonging to the Energy sources impact area.
for COMPANY_ID in "${COMPANY_IDS[@]}"; do
echo "=== ESG Energy Sources: $COMPANY_ID ==="
curl "$BASE_URL/companies/$COMPANY_ID/esg?templateId=2.1.6.1" \
-H "companyapikey: $API_KEY"
echo
done
Example response (200):
{
"metadata": { "success": true },
"data": {
"companyId": "G3JITT4AM9L",
"environmental": {
"sectionId": "2.1",
"name": "Environmental",
"totalDataPoints": 4,
"answeredDataPoints": 3,
"dataPoints": [
{
"retracedId": "energy_source_grid",
"name": "Share of grid electricity",
"description": "Percentage of total energy consumption sourced from the national grid",
"impactArea": "Energy sources",
"impactAreaId": "2.1.6.1",
"templateId": "2.1.6.1",
"value": 62,
"unit": "%",
"year": 2023
},
{
"retracedId": "energy_source_solar",
"name": "Share of on-site solar energy",
"description": "Percentage of total energy consumption generated from on-site solar panels",
"impactArea": "Energy sources",
"impactAreaId": "2.1.6.1",
"templateId": "2.1.6.1",
"value": 28,
"unit": "%",
"year": 2023
},
{
"retracedId": "energy_source_renewable_cert",
"name": "Share of renewable energy certificates (RECs)",
"description": "Percentage of electricity consumption covered by renewable energy certificates",
"impactArea": "Energy sources",
"impactAreaId": "2.1.6.1",
"templateId": "2.1.6.1",
"value": 10,
"unit": "%",
"year": 2023
},
{
"retracedId": "energy_source_fossil",
"name": "Share of fossil fuel energy",
"description": "Percentage of total energy consumption sourced from fossil fuels",
"impactArea": "Energy sources",
"impactAreaId": "2.1.6.1",
"templateId": "2.1.6.1",
"value": null,
"unit": "%",
"year": null
}
]
},
"social": {
"sectionId": "2.2",
"name": "Social",
"totalDataPoints": 0,
"answeredDataPoints": 0,
"dataPoints": []
},
"governance": {
"sectionId": "2.3",
"name": "Governance",
"totalDataPoints": 0,
"answeredDataPoints": 0,
"dataPoints": []
}
}
}
How to read it:
- The response always contains three sections —
environmental(2.1),social(2.2),governance(2.3). WithtemplateId=2.1.6.1, onlyenvironmentalcarries data points. - Data points with
value: nullhave not been filled in by the supplier.valueis polymorphic — percentages and quantities come as numbers, but other data points can hold strings or booleans. totalDataPoints/answeredDataPointsare counts after your filters are applied, not the size of the company's whole ESG profile.
ESG filter semantics
All filters combine with AND:
| Query param | Matching | Example |
|---|---|---|
templateId |
Exact match on the template/section ID | templateId=2.1.6.1 (Energy sources) |
retracedId |
Exact match on a specific data point | retracedId=energy_source_grid |
name |
Case-insensitive partial match on the data point name | name=solar |
impactArea |
Case-insensitive partial match on the impact area label | impactArea=energy |
When a company returns 404
GET /companies/:id/esg responds 404 company_not_found when the company has no ESG profile visible to you — either the ID is wrong, or the supplier hasn't shared a company profile with your network. There is no separate 403; missing access looks identical to a missing company. Handle this per supplier and continue with the rest (the collection script below does).
Step 4 — Fetch material composition
Material composition is structured in two layers: material headers (a named composition, e.g. "Shell Fabric") and material lines (the individual fibres/materials, organized as a tree). The full write model — including inheritance and copy-on-write — is covered in the Materials Guide; for LCA collection you only need to read.
4a. List material headers for the product
styleId accepts a style, variant, or SKU ID. Children automatically hold links to compositions created on their parent, so querying a SKU also surfaces the style's composition.
curl "$BASE_URL/material-headers?styleId=$STYLE_ID&page=1&limit=50" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
},
"data": [
{
"id": "mtrialhdr_01KTSC4N9GE3Q0V2J6M8R1WXYZ",
"name": "Shell",
"forCompanyId": "G3JITT4AM9L",
"description": "Outer body material composition",
"link": {
"styleId": "style_01KMZMMMW8JA3S1RVX1PS8E19S",
"isMainMaterial": true,
"isOwner": true
},
"createdAt": "2026-03-30T15:10:00.000Z",
"createdByUserId": "user-1",
"createdByCompanyId": "G3JITT4AM9L",
"updatedAt": "2026-03-30T15:10:00.000Z",
"updatedByUserId": "user-1",
"updatedByCompanyId": "G3JITT4AM9L"
}
]
}
A product can have several headers (shell, lining, trims). link.isMainMaterial marks the product's primary composition — usually the one you want for the LCA. link.isOwner tells you whether this product owns the composition or inherits it from its parent.
MATERIAL_HEADER_ID="mtrialhdr_01KTSC4N9GE3Q0V2J6M8R1WXYZ"
4b. List material lines for the header
Add include=rawMaterials,countriesOfOrigin to resolve the raw material catalog entries and country details in the same call.
curl "$BASE_URL/material-lines?materialHeaderId=$MATERIAL_HEADER_ID&include=rawMaterials,countriesOfOrigin&page=1&limit=50" \
-H "companyapikey: $API_KEY"
Response (200):
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 50, "total": 2, "totalPages": 1 }
},
"data": [
{
"id": "mtrialln_01KTSC5A2B3C4D5E6F7G8H9J0K",
"materialHeaderId": "mtrialhdr_01KTSC4N9GE3Q0V2J6M8R1WXYZ",
"rawMaterialId": "COTTON_BALE",
"percentage": 95,
"weights": 120,
"weightUnit": "GSM",
"parentId": null,
"hierarchy": 0,
"position": 100,
"countriesOfOrigin": ["IN"],
"createdAt": "2026-03-30T15:10:00.000Z",
"rawMaterial": {
"id": "COTTON_BALE",
"name": "Cotton bale",
"category": "NATURAL_MATERIAL",
"isRecycled": false,
"isSynthetic": false
},
"countries": [
{
"countryCode": "IN",
"countryName": "India",
"region": "Asia"
}
]
},
{
"id": "mtrialln_01KTSC5A2B3C4D5E6F7G8H9J1L",
"materialHeaderId": "mtrialhdr_01KTSC4N9GE3Q0V2J6M8R1WXYZ",
"rawMaterialId": "ELASTANE_FIBER",
"percentage": 5,
"weights": null,
"weightUnit": null,
"parentId": null,
"hierarchy": 0,
"position": 200,
"countriesOfOrigin": ["DE"],
"createdAt": "2026-03-30T15:10:01.000Z",
"rawMaterial": {
"id": "ELASTANE_FIBER",
"name": "Elastane fiber",
"category": "SYNTHETIC_MATERIAL",
"isRecycled": false,
"isSynthetic": true
},
"countries": [
{
"countryCode": "DE",
"countryName": "Germany",
"region": "Europe"
}
]
}
]
}
How to read the lines:
- Lines form a tree. Rebuild it client-side from
parentId(root lines haveparentId: null,hierarchy: 0); child lines describe the breakdown of their parent (e.g. a "Recycled cotton" line under a blended yarn). Order siblings byposition. percentageis relative to the parent level — sibling percentages under the same parent sum to 100.countriesOfOriginis an ISO 3166-1 alpha-2 code array (where the material was sourced).rawMaterialIdreferences Retraced's raw-material catalog; therawMaterialobject (viainclude=rawMaterials) carries the category andisRecycled/isSyntheticflags relevant for impact factors.
Full LCA Collection Script
Complete bash script that collects all four data sets for a given product ID.
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="https://publicapi.retraced.com/api/v2"
API_KEY="your-api-key"
STYLE_ID="style_01KMZMMMW8JA3S1RVX1PS8E19S"
api_get() { curl -s "$BASE_URL$1" -H "companyapikey: $API_KEY"; }
echo "=== Step 1a: List styles ==="
api_get "/styles?level=style&page=1&limit=50" | python3 -m json.tool
echo "=== Step 1b: List variants ==="
api_get "/styles?level=variant&styleId=$STYLE_ID&page=1&limit=50" | python3 -m json.tool
echo "=== Step 1c: List SKUs (first variant — adjust as needed) ==="
VARIANT_ID=$(api_get "/styles?level=variant&styleId=$STYLE_ID&page=1&limit=1" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data'][0]['id'])")
api_get "/styles?level=sku&variantId=$VARIANT_ID&page=1&limit=50" | python3 -m json.tool
echo "=== Step 2: Supply chain ==="
SUPPLY_CHAIN=$(api_get "/supply-chains/$STYLE_ID")
echo "$SUPPLY_CHAIN" | python3 -m json.tool
echo "$SUPPLY_CHAIN" > supply_chain.json
echo "=== Step 3: ESG energy sources per supplier ==="
COMPANY_IDS=$(echo "$SUPPLY_CHAIN" \
| python3 -c "
import sys, json
sc = json.load(sys.stdin)['data']
ids = {n['companyId'] for g in sc['nodesByProductionProcesses'] for n in g['nodes'] if n['companyId']}
print('\n'.join(ids))
")
for COMPANY_ID in $COMPANY_IDS; do
echo "--- $COMPANY_ID ---"
# Some suppliers have no shared ESG profile → 404 company_not_found; continue
api_get "/companies/$COMPANY_ID/esg?templateId=2.1.6.1" | python3 -m json.tool || true
done
echo "=== Step 4a: Material headers ==="
MATERIAL_HEADERS=$(api_get "/material-headers?styleId=$STYLE_ID&page=1&limit=50")
echo "$MATERIAL_HEADERS" | python3 -m json.tool
echo "=== Step 4b: Material lines ==="
HEADER_IDS=$(echo "$MATERIAL_HEADERS" \
| python3 -c "import sys, json; d=json.load(sys.stdin); print('\n'.join(h['id'] for h in d['data']))")
for HEADER_ID in $HEADER_IDS; do
echo "--- Header: $HEADER_ID ---"
api_get "/material-lines?materialHeaderId=$HEADER_ID&include=rawMaterials,countriesOfOrigin&page=1&limit=50" \
| python3 -m json.tool
done
echo "=== Done ==="
Quick Reference
| Data | Endpoint | Key parameter |
|---|---|---|
| List styles | GET /styles?level=style |
nameOrCode to search |
| List variants | GET /styles?level=variant |
styleId (parent style) |
| List SKUs | GET /styles?level=sku |
variantId (parent variant) |
| Supply chain | GET /supply-chains/:id |
accepts style, variant, or SKU ID |
| ESG energy sources | GET /companies/:companyId/esg?templateId=2.1.6.1 |
one call per supplier |
| Material headers | GET /material-headers?styleId= |
accepts style, variant, or SKU ID |
| Material lines | GET /material-lines?materialHeaderId= |
include=rawMaterials,countriesOfOrigin |
Gotchas Checklist
- Empty supply chain ≠ error.
nodesByProductionProcesses: []with a 200 means nothing is mapped (or the story is inactive);404 not_foundmeans the product ID doesn't exist. - Query any level. Supply chains and materials inherit upward — a SKU query falls back to the variant's/style's data automatically.
- ESG 404s are normal.
company_not_foundusually means the supplier hasn't shared a profile with your network. Skip and continue. - ESG counts are filtered counts.
totalDataPoints/answeredDataPointsdescribe the filtered result set, not the full profile. - Material percentages are per tree level. Siblings under the same parent sum to 100; don't sum across hierarchy levels.
- Weight inherits. A
nullSKU weight may still be resolvable from the parent style; checkisWeightAvailable. - Boolean query filters on
/stylesaccept onlytrueorfalse(isArchived,isComponent, …) — any other value is rejected with a400; omit the parameter to skip the filter. - List
limitis capped at 100 — page through large catalogues withpage, or useupdatedAfterUnixMsfor incremental pulls.
Related Reading
- Materials Guide — the full material composition model: trees, percentages, inheritance, copy-on-write
- BOM Guide — component-level Bills of Materials, if you need per-component breakdowns
- Products Guide — the Style → Variant → SKU hierarchy and field inheritance
- API Reference — interactive endpoint and schema documentation
- All integration guides