Skip to main content

Understanding Purchased Goods Emissions

Purchased goods and services emissions are indirect greenhouse gas emissions from the extraction, production, and transportation of goods and services acquired by your organization. Under ISO 14064-1 Category 4, this typically represents:
  • Raw materials: Metals, plastics, chemicals, wood, textiles
  • Intermediate products: Components, parts, packaging materials
  • Services: Professional services, IT services, maintenance, consulting
┌─────────────────────────────────────────────────────────────────────────────┐
│          ISO 14064-1 CATEGORY 4.3: Purchased Goods & Services               │
├─────────────────────┬─────────────────────┬─────────────────────────────────┤
│  Raw Materials      │  Intermediate       │  Services                       │
│                     │  Products           │                                 │
├─────────────────────┼─────────────────────┼─────────────────────────────────┤
│  • Metals           │  • Components       │  • IT services                  │
│  • Plastics         │  • Packaging        │  • Professional services        │
│  • Chemicals        │  • Semi-finished    │  • Maintenance                  │
│  • Textiles         │  • Electronics      │  • Consulting                   │
└─────────────────────┴─────────────────────┴─────────────────────────────────┘
Why Category 4.3 MattersFor most organizations, purchased goods and services represent 40-80% of total emissions. This makes Category 4.3 the single most important area for understanding and reducing your carbon footprint.Typical Category 4.3 Contribution:
  • Manufacturing: 60-80% of indirect emissions
  • Retail: 70-90% of indirect emissions
  • Services: 30-50% of indirect emissions

Prerequisites

Before starting, ensure you have:
  • Dcycle API credentials (get them here)
  • Purchase data: invoices, procurement records, or ERP exports
  • Knowledge of your spending categories (for spend-based method) or physical quantities (for activity-based method)
Using the Dcycle App?You can also manage purchases through our web interface:

Data Map: Purchased Goods & Services Requirements Overview

┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                   PURCHASED GOODS & SERVICES DATA REQUIREMENTS                          │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                         │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │ SUPPLIER SETUP (Optional)                                                       │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │  Required Fields           Optional Fields           For Custom EFs            │   │
│  │  ─────────────────         ───────────────           ─────────────────         │   │
│  │  • business_name           • contact_email           • EPD reference           │   │
│  │  • country                 • sector                  • Certification           │   │
│  │  • tax_id                  • supplier_code           • Verification date       │   │
│  │                                                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                         │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │ PURCHASE DATA                                                                   │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │  Spend-Based               Activity-Based            Supplier-Specific         │   │
│  │  ────────────────────      ────────────────          ─────────────────         │   │
│  │  • quantity (€)            • quantity (kg, units)    • quantity                │   │
│  │  • unit_id (€)             • unit_id (kg, m³, etc.)  • unit_id                 │   │
│  │  • sector                  • product_name            • custom_emission_        │   │
│  │  • product_name            • sector                    factor_id               │   │
│  │  • country                 • country                 • supplier_id             │   │
│  │  • purchase_date           • purchase_date           • purchase_date           │   │
│  │                            • supplier_id             • recycled (%)            │   │
│  │                                                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                         │
└─────────────────────────────────────────────────────────────────────────────────────────┘

Calculation Methods

Dcycle supports three calculation methods for purchased goods and services, each with different accuracy levels:

Data Quality Hierarchy

┌────────────────────────────────────────────────────────────────────────────────────────┐
│                            DATA QUALITY HIERARCHY                                       │
├────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                        │
│  Level 1: Supplier-Specific Data ─────────────────────────────────── HIGHEST ACCURACY │
│  ├─ EPDs, Product Carbon Footprints, Supplier PCFs                                    │
│  ├─ Accuracy: ±5-15%                                                                  │
│  └─ Use: custom_emission_factor_id                                                    │
│                                                                                        │
│  Level 2: Activity-Based Data ─────────────────────────────────────── MEDIUM ACCURACY │
│  ├─ Product category + physical quantity (kg, m³, units)                              │
│  ├─ Accuracy: ±20-40%                                                                 │
│  └─ Use: quantity + unit_id + sector/product_name                                     │
│                                                                                        │
│  Level 3: Spend-Based Data ─────────────────────────────────────────── LOWER ACCURACY │
│  ├─ Only monetary value + category                                                    │
│  ├─ Accuracy: ±50-100%                                                                │
│  └─ Use: quantity (€) + unit_id (€) + sector/product_name                             │
│                                                                                        │
└────────────────────────────────────────────────────────────────────────────────────────┘
The spend-based method uses economic input-output (EEIO) emission factors based on the monetary value of purchases.
Spend (€) → Sector/Product Category → Exiobase EF → CO₂e
     ↓              ↓                      ↓           ↓
Invoice amount   Product mapping      kg CO₂e/€    Total emissions
Key characteristics:
  • Uses Exiobase 3.8.2 input-output emission factors
  • Emission factors in kg CO₂e per € (or other currency)
  • Covers all economic sectors and product categories
  • Lower accuracy but broad coverage
For spend-based calculations, Dcycle uses emission factors from:
  • Exiobase 3.8.2 - Multi-Regional Environmentally Extended Supply-Use Tables
  • Covers 44 countries and 200+ product categories
  • Source: Exiobase
Factors are automatically selected based on:
  • Sector/product category
  • Supplier country (or your organization’s country)
  • Purchase year
Spend-based emissions are calculated as:CO₂e = Spend Amount (€) × Economic Intensity Factor (kg CO₂e/€)Where:
  • Spend Amount: Monetary value of the purchase
  • Economic Intensity Factor: Exiobase emission factor for the sector/product
Example (IT Services):
€15,000 × 0.15 kg CO₂e/€ = 2,250 kg CO₂e
Note: Spend-based factors have high uncertainty (±50-100%) and should be used when physical quantities are unavailable.
Automatic Method SelectionDcycle automatically selects the calculation method based on the data provided:
  • custom_emission_factor_id provided → Supplier-specific method
  • quantity + physical unit_id provided → Activity-based method
  • quantity in currency unit (€) → Spend-based method

Recording Purchases

Data Flow

1

Set Up Suppliers (Optional)

Create supplier records to organize purchases and enable supplier-level reporting
2

Choose Calculation Method

Determine which method to use based on available data (spend-based, activity-based, or supplier-specific)
3

Create Purchases

Record purchases via API or bulk CSV upload with appropriate fields for chosen method
4

Automatic Calculation

Dcycle automatically calculates CO₂e using Exiobase (spend-based), activity factors, or custom EFs
5

Query and Analyze

View emissions by supplier, category, or period for hotspot identification

Set Up Purchase Suppliers

FieldTypeRequiredDescriptionExample
business_namestringSupplier company name"Green Materials Co"
tax_idstringTax identification number"B12345678"
countrystringSupplier country (ISO code)"ES", "FR", "DE"
sectorstringBusiness sector"Manufacturing"
contact_emailstringContact email"[email protected]"
supplier_codestringSectorial code (SIC (US 1987)/CNAE (2009))"3331"
Where to get this data:
  • Business name/Tax ID: From supplier invoices or contracts
  • Country: Supplier headquarters or production location
  • Sector: Industry classification (helps with reporting)
Organize purchases by supplier to enable supplier-level emissions reporting and engagement:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Create a purchase supplier
supplier_data = {
    "business_name": "Green Materials Co",
    "tax_id": "B12345678",
    "country": "ES",
    "sector": "Manufacturing",
    "contact_email": "[email protected]",
}

response = requests.post(
    "https://api.dcycle.io/api/v1/purchase_suppliers",
    headers=headers,
    json=supplier_data,
)

supplier = response.json()
print(f"✅ Supplier created: {supplier['id']}")
print(f"   Name: {supplier['business_name']}")
print(f"   Country: {supplier['country']}")
Supplier Organization Best Practices
  • Group purchases by supplier for better hotspot analysis
  • Include supplier country for accurate regional emission factors
  • Use consistent supplier codes across your ERP and Dcycle

Create a Spend-Based Purchase

FieldTypeRequiredDescriptionExample
descriptionstringPurchase description"IT consulting Q1"
sectorstringEconomic sector"Computer programming, consultancy"
product_namestringProduct/service category"Computer programming services"
quantitynumberMonetary value spent15000
unit_idUUIDCurrency unit (€)"eur-unit-uuid"
countrystringSupplier country"ES"
purchase_datedateDate of purchase"2024-03-15"
supplier_idUUIDLinked supplier"supplier-uuid"
purchase_typestringMust be "spend_based""spend_based"
Where to get this data:
  • Quantity: From invoices, payment records, or ERP exports
  • Sector/Product: Map from your expense categories (see Exiobase mapping)
  • Country: Supplier’s country of origin
Use the spend-based method when you only have monetary values:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Get the EUR unit for spend-based purchases
units = requests.get(
    "https://api.dcycle.io/api/v1/units",
    headers=headers,
    params={"page": 1, "size": 100}
).json()

eur_unit = next(u for u in units['items'] if u['abbreviation'] == '€')

# Create spend-based purchase (IT consulting services)
purchase_data = {
    "description": "IT consulting services Q1 2024",
    "sector": "Computer programming, consultancy and related activities",
    "product_name": "Computer programming, consultancy and related services",
    "quantity": 15000,  # €15,000 spent
    "unit_id": eur_unit['id'],  # EUR unit
    "country": "ES",  # Supplier country
    "purchase_date": "2024-03-15",
    "supplier_id": "your-supplier-uuid",  # Optional
    "purchase_type": "spend_based",
}

response = requests.post(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    json=purchase_data,
)

purchase = response.json()
print(f"✅ Spend-based purchase created: {purchase['id']}")
print(f"   Amount: €{purchase['quantity']:,.2f}")
print(f"   CO₂e: {purchase.get('co2e', 'Calculating...')} kg")
print(f"   Method: Spend-based (Exiobase 3.8.2)")
print(f"   ISO 14064-1 Category: 4.3 (Purchased Goods)")
Spend-Based Accuracy LimitationsSpend-based factors have high uncertainty (±50-100%) because:
  • Price ≠ emissions (expensive ≠ high emissions)
  • Doesn’t account for specific products or supplier practices
  • Currency fluctuations affect results
Use spend-based as a starting point, then improve data quality for high-impact categories.

Create an Activity-Based Purchase

FieldTypeRequiredDescriptionExample
descriptionstringPurchase description"Aluminum sheets for production"
sectorstringProduct sector"Manufacture of basic metals"
product_namestringSpecific product"Aluminium and aluminium products"
quantitynumberPhysical quantity1000
unit_idUUIDPhysical unit (kg, m³, etc.)"kg-unit-uuid"
countrystringCountry of origin"ES"
purchase_datedateDate of purchase"2024-03-15"
supplier_idUUIDLinked supplier"supplier-uuid"
purchase_typestringMust be "activity_based""activity_based"
recyclednumberRecycled content (0-1)0.3 (30% recycled)
Where to get this data:
  • Quantity: From delivery notes, bills of materials, or inventory systems
  • Unit: Match the physical unit of the product (kg for materials, m³ for liquids)
  • Recycled: Ask supplier for recycled content percentage
Use the activity-based method when you have physical quantities:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Get the kg unit for activity-based purchases
units = requests.get(
    "https://api.dcycle.io/api/v1/units",
    headers=headers,
    params={"page": 1, "size": 100}
).json()

kg_unit = next(u for u in units['items'] if u['abbreviation'] == 'kg')

# Create activity-based purchase (aluminum sheets)
purchase_data = {
    "description": "Aluminum sheets for Q1 production",
    "sector": "Manufacture of basic metals",
    "product_name": "Aluminium and aluminium products",
    "quantity": 1000,  # 1,000 kg
    "unit_id": kg_unit['id'],  # kg unit
    "country": "ES",  # Country of origin
    "purchase_date": "2024-03-15",
    "supplier_id": "your-supplier-uuid",  # Recommended
    "purchase_type": "activity_based",
    "recycled": 0.0,  # 0% recycled content (optional)
}

response = requests.post(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    json=purchase_data,
)

purchase = response.json()
print(f"✅ Activity-based purchase created: {purchase['id']}")
print(f"   Quantity: {purchase['quantity']:,.0f} kg")
print(f"   CO₂e: {purchase.get('co2e', 'Calculating...')} kg")
print(f"   Method: Activity-based")
print(f"   ISO 14064-1 Category: 4.3 (Purchased Goods)")
Track Recycled ContentIf your supplier provides recycled materials, use the recycled field (0-1) to indicate the percentage. This:
  • Improves calculation accuracy
  • Enables tracking of circular economy metrics
  • Supports supplier engagement on recycled content

Create a Supplier-Specific Purchase

FieldTypeRequiredDescriptionExample
descriptionstringPurchase description"Recycled aluminum (EPD verified)"
quantitynumberPhysical quantity1000
unit_idUUIDPhysical unit"kg-unit-uuid"
purchase_datedateDate of purchase"2024-03-15"
supplier_idUUIDLinked supplier"supplier-uuid"
custom_emission_factor_idUUIDCustom EF from supplier EPD"custom-ef-uuid"
countrystringSupplier country"ES"
Where to get this data:
  • Custom Emission Factor: Create from supplier EPD/PCF (see below)
  • Quantity: From delivery notes or purchase orders
  • Supplier ID: From your supplier setup
For highest accuracy, use supplier-provided emission data (EPDs, PCFs):
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Step 1: Create a custom emission factor group for the supplier
group_data = {
    "name": "Green Materials Co - 2024 Product Line",
    "description": "EPD-verified emission factors from Green Materials Co",
    "category": "purchases",
    "ghg_type": 1,  # 1 = Fossil
}

group = requests.post(
    "https://api.dcycle.io/api/v1/custom_emission_groups",
    headers=headers,
    json=group_data,
).json()

print(f"✅ Custom EF group created: {group['id']}")

# Step 2: Add emission factor values from the supplier's EPD
kg_unit_id = "61743a63-ff70-459c-9567-5eee8f7dfd5c"  # kg unit UUID

factor_data = {
    "ef_name": "Recycled Aluminum Sheet - Green Materials Co (EPD S-P-12345)",
    "unit_id": kg_unit_id,
    "factor_uploaded_by": "[email protected]",
    "tag": "advanced",
    "uncertainty_grade": 12,  # Low uncertainty (EPD-verified)
    "factor_start_date": "2024-01-01",
    "factor_end_date": "2024-12-31",
    "additional_docs": "EPD No. S-P-12345, Bureau Veritas verified",
    "emission_factor_values": [
        {"gas_type": "CO2", "value": 2.15},  # kg CO2 per kg
        {"gas_type": "CH4", "value": 0.008},  # kg CH4 per kg
        {"gas_type": "N2O", "value": 0.002},  # kg N2O per kg
    ],
}

factor = requests.post(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{group['id']}",
    headers=headers,
    json=factor_data,
).json()

print(f"✅ Custom emission factor created: {factor['id']}")

# Step 3: Create purchase using the custom emission factor
purchase_data = {
    "description": "Recycled aluminum sheets from Green Materials Co",
    "quantity": 1000,  # 1,000 kg
    "unit_id": kg_unit_id,
    "purchase_date": "2024-03-15",
    "supplier_id": "your-supplier-uuid",
    "custom_emission_factor_id": factor['id'],  # Use supplier's verified factor
}

response = requests.post(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    json=purchase_data,
)

purchase = response.json()
print(f"✅ Supplier-specific purchase created: {purchase['id']}")
print(f"   Quantity: {purchase['quantity']:,.0f} kg")
print(f"   CO₂e: {purchase.get('co2e', 'Calculating...')} kg")
print(f"   Method: Supplier-specific (EPD S-P-12345)")
print(f"   ISO 14064-1 Category: 4.3 (Purchased Goods)")

# Compare with generic factor
generic_co2e = 1000 * 8.5  # Generic aluminum EF
supplier_co2e = 1000 * 2.15  # Supplier's recycled aluminum EF
savings = generic_co2e - supplier_co2e
print(f"\n📊 Emission savings vs generic: {savings:,.0f} kg CO₂e ({savings/generic_co2e*100:.0f}%)")
Why Supplier-Specific MattersUsing supplier-specific data (EPDs, PCFs) provides:
  • Higher accuracy (±5-15% vs ±50-100% for spend-based)
  • Recognition for low-carbon suppliers (recycled materials, renewable energy)
  • Data for supplier engagement programs
  • Credibility for external reporting and audits
Start with high-emission categories: typically metals, chemicals, electronics.

Bulk Upload Purchases

For large datasets from ERP systems:

CSV Format for Purchases

description,sector,product_name,quantity,unit_id,country,purchase_date,supplier_id,purchase_type,recycled
"Aluminum sheets Q1",Manufacture of basic metals,Aluminium and aluminium products,1000,kg-unit-uuid,ES,2024-03-01,supplier-uuid-1,activity_based,0.0
"Steel beams Q1",Manufacture of basic metals,Basic iron and steel,5000,kg-unit-uuid,DE,2024-03-05,supplier-uuid-2,activity_based,0.3
"IT consulting",Computer programming consultancy,Computer programming services,15000,eur-unit-uuid,ES,2024-03-10,supplier-uuid-3,spend_based,

Upload Process

# Get presigned URL for bulk upload
upload_response = requests.post(
    "https://api.dcycle.io/api/v1/purchases/bulk/csv",
    headers=headers,
    json={"file_name": "q1_2024_purchases.csv"},
).json()

# Upload CSV to presigned URL
with open('q1_2024_purchases.csv', 'rb') as f:
    requests.put(upload_response['upload_url'], data=f)

print(f"✅ CSV uploaded, processing will begin automatically")
print(f"   Check processing status in the Dcycle App")

Query Purchases and Emissions

Get Purchases by Period

# Query purchases for a specific period
response = requests.get(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    params={
        "page": 1,
        "size": 50,
        "start_date": "2024-01-01",
        "end_date": "2024-03-31",
    },
).json()

print(f"📊 Q1 2024 Purchases (Category 4.3):")
total_co2e = 0
for purchase in response["items"]:
    print(f"   {purchase['description']}")
    print(f"   Quantity: {purchase['quantity']} {purchase['unit']}")
    print(f"   CO₂e: {purchase['co2e']:.2f} kg")
    print(f"   Method: {purchase['purchase_type']}")
    print()
    total_co2e += purchase['co2e']

print(f"   Total CO₂e: {total_co2e:,.2f} kg")

Get Supplier Emissions Report

# Get emissions by supplier
supplier_id = "your-supplier-uuid"

response = requests.get(
    f"https://api.dcycle.io/api/v1/purchase_suppliers/{supplier_id}",
    headers=headers,
    params={
        "start_date": "2024-01-01",
        "end_date": "2024-12-31",
    },
).json()

print(f"📊 Supplier Report: {response['business_name']}")
print(f"   Total purchases: {response['total_purchases']}")
print(f"   Total CO₂e: {response['total_co2e']:,.2f} kg")
Best Practice: Prioritize Data Quality ImprovementFor complete Category 4.3 accounting:
  1. Start with spend-based for broad coverage
  2. Identify hotspots (top 10-20 categories by emissions)
  3. Improve data quality for hotspots (move to activity-based)
  4. Engage key suppliers for EPDs/PCFs (top 20% by emissions)
Goal: Move from 100% spend-based to 50%+ activity/supplier-specific.

Exiobase Sector and Product Mapping

Dcycle uses Exiobase 3.8.2 for spend-based emission factors. Here are the most common sectors:
SectorExample ProductsTypical EF Range (kg CO₂e/€)
Manufacture of basic metalsSteel, aluminum, copper0.8 - 2.5
Manufacture of chemicalsIndustrial chemicals, plastics0.5 - 1.5
Manufacture of electrical equipmentElectronics, components0.3 - 0.8
Computer programming, consultancyIT services, software0.1 - 0.3
Manufacture of textilesFabrics, clothing0.4 - 1.2
Manufacture of paperPackaging, office supplies0.3 - 0.8
Professional servicesConsulting, legal0.1 - 0.2
Contact Dcycle support for the complete Exiobase sector and product mapping for your industry.The mapping includes:
  • 200+ product categories
  • 44 countries with regional factors
  • Annual updates based on economic data
If your expense categories don’t match Exiobase sectors directly, you can:
  1. Use the closest matching sector
  2. Create custom mappings via the API
  3. Contact Dcycle support for assistance
Consistent mapping is key for year-over-year comparisons.

Troubleshooting

Issue: High Uncertainty in Spend-Based Calculations

# Check calculation method and improve data quality
purchase = requests.get(
    f"https://api.dcycle.io/api/v1/purchases/{purchase_id}",
    headers=headers,
).json()

if purchase['purchase_type'] == 'spend_based':
    print("⚠️  Using spend-based method (high uncertainty)")
    print("💡 Recommendations:")
    print("   1. Collect physical quantities from supplier")
    print("   2. Request product specifications")
    print("   3. Ask supplier for EPD/PCF data")

Issue: Can’t Find Appropriate Sector/Product

# Use the most specific category available
# If unsure, use broader category and refine later

# Too broad: "Manufacturing"
# Better: "Manufacture of basic metals"
# Best: "Aluminium and aluminium products"

# You can update the sector later:
requests.patch(
    f"https://api.dcycle.io/api/v1/purchases/{purchase_id}",
    headers=headers,
    json={
        "sector": "Manufacture of basic metals",
        "product_name": "Aluminium and aluminium products",
    },
)

Issue: Supplier Data Not Available

# Track without supplier initially, link later
purchase_data = {
    "description": "Office supplies Q1",
    "sector": "Manufacture of paper and paper products",
    "product_name": "Paper and paper products",
    "quantity": 500,  # €500
    "unit_id": eur_unit_id,
    "purchase_date": "2024-03-15",
    "purchase_type": "spend_based",
    # supplier_id: omitted - can add later
}

# Later, link to supplier:
requests.patch(
    f"https://api.dcycle.io/api/v1/purchases/{purchase_id}",
    headers=headers,
    json={"supplier_id": "supplier-uuid"},
)

Next Steps