Skip to main content

Understanding Scope 3 Category 1

Purchased goods and services emissions are indirect greenhouse gas emissions from the extraction, production, and transportation of goods and services acquired by your organization. According to the GHG Protocol Scope 3 Standard, Category 1 typically represents:
  • Raw materials: Metals, plastics, chemicals, wood, textiles
  • Intermediate products: Components, parts, packaging materials
  • Services: Professional services, IT services, maintenance, consulting
┌─────────────────────────────────────────────────────────────────────────────┐
│                    SCOPE 3 CATEGORY 1: 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 1 MattersFor most organizations, purchased goods and services represent 40-80% of total emissions. This makes Category 1 the single most important area for understanding and reducing your carbon footprint.Typical Category 1 Contribution:
  • Manufacturing: 60-80% of Scope 3
  • Retail: 70-90% of Scope 3
  • Services: 30-50% of Scope 3

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

Before diving into the calculations, here’s a complete overview of the data you’ll need:
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                   PURCHASED GOODS & SERVICES DATA REQUIREMENTS                          │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                         │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │ SUPPLIER SETUP (Step 4.1)                                                       │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │  Required Fields           Optional Fields           For Custom EFs            │   │
│  │  ─────────────────         ───────────────           ─────────────────         │   │
│  │  • business_name           • contact_email           • EPD reference           │   │
│  │  • country                 • sector                  • Certification           │   │
│  │  • tax_id                  • supplier_code           • Verification date       │   │
│  │                                                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                         │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │ PURCHASE DATA (Steps 4.2 - 4.4)                                                 │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │  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

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

Step 4.1: 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

Step 4.2: 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)")
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.

Step 4.3: 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")
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

Step 4.4: 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)")

# 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:")
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 Scope 3 Category 1 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

Now that you understand Category 1, continue with: