> ## Documentation Index
> Fetch the complete documentation index at: https://code.dcycle.io/llms.txt
> Use this file to discover all available pages before exploring further.

# List Purchases

> Get a paginated list of purchased goods and services in your organization

# List Purchases

Retrieve all purchases (Scope 3 - Category 1: Purchased Goods and Services) registered in your organization with pagination support and flexible filtering options.

<Note>
  Purchases represent **Scope 3 emissions** from goods and services your organization buys. This is typically one of the largest emission categories for most organizations.
</Note>

## Request

### Headers

<ParamField header="x-api-key" type="string" required>
  Your API key for authentication

  **Example:** `sk_live_1234567890abcdef`
</ParamField>

<ParamField header="x-organization-id" type="string" required>
  Your organization UUID

  **Example:** `ff4adcc7-8172-45fe-9cf1-e90a6de53aa9`
</ParamField>

<ParamField header="x-user-id" type="string" required>
  Your user UUID

  **Example:** `a1b2c3d4-e5f6-7890-abcd-ef1234567890`
</ParamField>

### Query Parameters

<ParamField query="page" type="integer" default="1">
  Page number for pagination

  **Example:** `1`
</ParamField>

<ParamField query="size" type="integer" default="50">
  Number of items per page (max: 100)

  **Example:** `50`
</ParamField>

<ParamField query="filter_by" type="string">
  Advanced filtering criteria (format: `field:operator:value` or `field:value`)

  **Supported operators:**

  * `eq` - Equals
  * `neq` - Not equals
  * `in` - In list
  * `nin` - Not in list
  * `gt` - Greater than
  * `gte` - Greater than or equal
  * `lt` - Less than
  * `lte` - Less than or equal

  **Example:** `"status:active"` or `"sector:eqIT Services"`
</ParamField>

<ParamField query="sort_by" type="string">
  Sort criteria (format: `field:asc` or `field:desc`)

  **Sortable fields:**

  * `purchase_date`
  * `quantity`
  * `co2e`
  * `sector`
  * `status`

  **Example:** `"co2e:desc"`
</ParamField>

## Response

<ResponseField name="page" type="integer">
  Current page number
</ResponseField>

<ResponseField name="size" type="integer">
  Number of items per page
</ResponseField>

<ResponseField name="total" type="integer">
  Total count of **active** purchases
</ResponseField>

<ResponseField name="total2" type="integer">
  Total count of purchases with **errors or in review** status
</ResponseField>

<ResponseField name="items" type="array">
  Array of purchase objects

  ### Purchase Object Fields:

  <ResponseField name="id" type="string">
    Unique purchase identifier (UUID v4)
  </ResponseField>

  <ResponseField name="organization_id" type="string">
    Organization UUID
  </ResponseField>

  <ResponseField name="quantity" type="float">
    Purchase quantity
  </ResponseField>

  <ResponseField name="unit_id" type="string">
    Unit UUID for the quantity
  </ResponseField>

  <ResponseField name="unit" type="object">
    Unit details object with `id`, `name`, `type` fields
  </ResponseField>

  <ResponseField name="sector" type="string">
    Economic sector code (NAICS or similar classification)

    **Examples:** `"IT Services"`, `"Manufacturing"`, `"Transportation"`
  </ResponseField>

  <ResponseField name="product_name" type="string">
    Product or service name

    **Examples:** `"Laptops"`, `"Cloud Services"`, `"Office Supplies"`
  </ResponseField>

  <ResponseField name="purchase_type" type="string">
    Type of purchase calculation method

    **Values:**

    * `spend_based` - Calculated based on monetary spend (most common)
    * `supplier_specific` - Uses supplier-specific emission factors
  </ResponseField>

  <ResponseField name="expense_type" type="string">
    Expense category

    **Values:** `"goods"`, `"services"`, `"capital_goods"`, `"other"`
  </ResponseField>

  <ResponseField name="supplier_id" type="string" optional>
    Supplier UUID (for spend\_based purchases)
  </ResponseField>

  <ResponseField name="supplier" type="object" optional>
    Supplier details object with `business_name` and `country` fields
  </ResponseField>

  <ResponseField name="purchase_date" type="datetime">
    Date of purchase (ISO 8601 format)
  </ResponseField>

  <ResponseField name="last_purchase_timestamp" type="datetime">
    Last update timestamp (ISO 8601 format)
  </ResponseField>

  <ResponseField name="recycled" type="float" optional>
    Percentage of recycled content (0.0 to 1.0)
  </ResponseField>

  <ResponseField name="country" type="string">
    ISO 3166-1 alpha-2 country code where purchase was made
  </ResponseField>

  <ResponseField name="frequency" type="string">
    Purchase frequency for recurring purchases

    **Values:** `"once"`, `"weekly"`, `"monthly"`, `"quarterly"`, `"yearly"`
  </ResponseField>

  <ResponseField name="description" type="string" optional>
    Purchase description or notes
  </ResponseField>

  <ResponseField name="status" type="string">
    Purchase status

    **Values:**

    * `active` - Successfully processed
    * `success` - Successfully processed (legacy)
    * `error` - Processing failed
    * `in_review` - Pending review
  </ResponseField>

  <ResponseField name="co2e" type="float">
    Total CO2 equivalent emissions in kg
  </ResponseField>

  <ResponseField name="ef" type="float" optional>
    Emission factor used for calculation (kg CO2e per unit)
  </ResponseField>

  <ResponseField name="displayed_ggss" type="boolean" optional>
    Whether to display GHG sector scope information
  </ResponseField>

  <ResponseField name="custom_emission_factor_id" type="string" optional>
    UUID of custom emission factor (if using supplier-specific method)
  </ResponseField>

  <ResponseField name="file_url" type="string" optional>
    URL of uploaded file (for bulk uploads)
  </ResponseField>

  <ResponseField name="file_id" type="string" optional>
    UUID of uploaded file
  </ResponseField>

  <ResponseField name="file_name" type="string" optional>
    Name of uploaded file
  </ResponseField>
</ResponseField>

## Example

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X GET "https://api.dcycle.io/api/v1/purchases?page=1&size=50&sort_by=co2e:desc" \
    -H "Authorization: Bearer ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_ID}" \
    -H "x-user-id: ${DCYCLE_USER_ID}"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import requests
  import os

  api_key = os.getenv("DCYCLE_API_KEY")
  org_id = os.getenv("DCYCLE_ORG_ID")
  user_id = os.getenv("DCYCLE_USER_ID")

  headers = {
      "Authorization": f"Bearer {api_key}",
      "x-organization-id": org_id,
      "x-user-id": user_id
  }

  # Get purchases sorted by emissions (highest first)
  params = {
      "page": 1,
      "size": 50,
      "sort_by": "co2e:desc"
  }

  response = requests.get(
      "https://api.dcycle.io/api/v1/purchases",
      headers=headers,
      params=params
  )

  purchases = response.json()
  print(f"Total active purchases: {purchases['total']}")
  print(f"Purchases with errors: {purchases['total2']}")

  # Display top emissions sources
  print("\nTop emission sources:")
  for purchase in purchases['items'][:10]:
      supplier_name = purchase['supplier'].get('business_name', 'N/A') if purchase['supplier'] else 'N/A'
      print(f"- {purchase['product_name']}: {purchase['co2e']:.2f} kg CO2e ({supplier_name})")
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const axios = require('axios');

  const apiKey = process.env.DCYCLE_API_KEY;
  const orgId = process.env.DCYCLE_ORG_ID;
  const userId = process.env.DCYCLE_USER_ID;

  const headers = {
    'Authorization': `Bearer ${apiKey}`,
    'x-organization-id': orgId,
    'x-user-id': userId
  };

  // Get purchases sorted by emissions (highest first)
  const params = {
    page: 1,
    size: 50,
    sort_by: 'co2e:desc'
  };

  axios.get('https://api.dcycle.io/api/v1/purchases', { headers, params })
    .then(response => {
      const purchases = response.data;
      console.log(`Total active purchases: ${purchases.total}`);
      console.log(`Purchases with errors: ${purchases.total2}`);

      // Display top emission sources
      console.log('\nTop emission sources:');
      purchases.items.slice(0, 10).forEach(purchase => {
        const supplierName = purchase.supplier?.business_name || 'N/A';
        console.log(`- ${purchase.product_name}: ${purchase.co2e.toFixed(2)} kg CO2e (${supplierName})`);
      });
    })
    .catch(error => console.error(error));
  ```
</CodeGroup>

### Successful Response

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "page": 1,
  "size": 50,
  "total": 245,
  "total2": 12,
  "items": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "organization_id": "org-uuid",
      "quantity": 25000.0,
      "unit_id": "eur-unit-uuid",
      "unit": {
        "id": "eur-unit-uuid",
        "name": "EUR",
        "type": "fiat_currency"
      },
      "sector": "IT Services",
      "product_name": "Cloud Computing Services",
      "purchase_type": "spend_based",
      "expense_type": "services",
      "supplier_id": "supplier-uuid",
      "supplier": {
        "business_name": "AWS EMEA SARL",
        "country": "ES"
      },
      "purchase_date": "2024-01-15T00:00:00Z",
      "last_purchase_timestamp": "2024-01-16T10:30:00Z",
      "recycled": null,
      "country": "ES",
      "frequency": "monthly",
      "description": "Monthly AWS cloud infrastructure costs",
      "status": "active",
      "co2e": 2450.75,
      "ef": 0.098,
      "displayed_ggss": true,
      "custom_emission_factor_id": null,
      "file_url": null,
      "file_id": null,
      "file_name": null
    },
    {
      "id": "b2c3d4e5-f6g7-8901-bcde-fg2345678901",
      "organization_id": "org-uuid",
      "quantity": 15000.0,
      "unit_id": "eur-unit-uuid",
      "unit": {
        "id": "eur-unit-uuid",
        "name": "EUR",
        "type": "fiat_currency"
      },
      "sector": "Office Supplies",
      "product_name": "Printer Paper",
      "purchase_type": "spend_based",
      "expense_type": "goods",
      "supplier_id": "supplier-uuid-2",
      "supplier": {
        "business_name": "Office Depot Spain",
        "country": "ES"
      },
      "purchase_date": "2024-01-10T00:00:00Z",
      "last_purchase_timestamp": "2024-01-10T14:22:00Z",
      "recycled": 0.3,
      "country": "ES",
      "frequency": "quarterly",
      "description": "Q1 2024 office paper supplies",
      "status": "active",
      "co2e": 1825.50,
      "ef": 0.122,
      "displayed_ggss": true,
      "custom_emission_factor_id": null,
      "file_url": null,
      "file_id": null,
      "file_name": null
    }
  ]
}
```

## Common Errors

### 400 Bad Request

**Cause:** Invalid query parameters or filter format

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "Invalid filter format",
  "code": "VALIDATION_ERROR"
}
```

**Solution:** Verify that filter\_by and sort\_by follow the correct format.

### 403 Forbidden

**Cause:** Organization ID doesn't match your API key or user doesn't belong to organization

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "Not authorized",
  "code": "FORBIDDEN"
}
```

**Solution:** Verify that `x-organization-id` matches your API key's organization.

## Use Cases

### Get Purchases Dashboard

Display all active purchases with highest emissions:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_purchases_dashboard():
    """Get purchases dashboard with top emitters"""

    response = requests.get(
        "https://api.dcycle.io/api/v1/purchases",
        headers=headers,
        params={
            "page": 1,
            "size": 100,
            "sort_by": "co2e:desc",
            "filter_by": "status:active"
        }
    )

    purchases = response.json()

    # Calculate totals
    total_emissions = sum(p['co2e'] or 0 for p in purchases['items'])
    total_spend = sum(
        p['quantity'] for p in purchases['items']
        if p['unit']['type'] == 'fiat_currency'
    )

    return {
        'purchases': purchases['items'],
        'total_active': purchases['total'],
        'total_errors': purchases['total2'],
        'total_emissions': total_emissions,
        'total_spend': total_spend
    }

# Usage
dashboard = get_purchases_dashboard()
print(f"Total emissions: {dashboard['total_emissions']:.2f} kg CO2e")
print(f"Total spend: {dashboard['total_spend']:.2f} EUR")
```

### Filter by Sector

Get all purchases in a specific sector:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_purchases_by_sector(sector_name):
    """Get purchases filtered by sector"""

    response = requests.get(
        "https://api.dcycle.io/api/v1/purchases",
        headers=headers,
        params={
            "filter_by": f"sector:eq{sector_name}",
            "page": 1,
            "size": 100
        }
    )

    purchases = response.json()

    print(f"Purchases in {sector_name}: {purchases['total']}")
    for purchase in purchases['items']:
        print(f"  - {purchase['product_name']}: {purchase['co2e']:.2f} kg CO2e")

    return purchases

# Example: Get all IT Services purchases
it_purchases = get_purchases_by_sector("IT Services")
```

### Filter by Date Range

Get purchases within a specific time period:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from datetime import datetime, timedelta

def get_recent_purchases(days=30):
    """Get purchases from the last N days"""

    # Note: Date filtering requires timestamp comparison
    # This example shows pagination through all results and client-side filtering
    all_purchases = []
    page = 1
    cutoff_date = datetime.now() - timedelta(days=days)

    while True:
        response = requests.get(
            "https://api.dcycle.io/api/v1/purchases",
            headers=headers,
            params={"page": page, "size": 100}
        )

        data = response.json()

        # Filter by date client-side
        for purchase in data['items']:
            purchase_date = datetime.fromisoformat(purchase['purchase_date'].replace('Z', '+00:00'))
            if purchase_date >= cutoff_date:
                all_purchases.append(purchase)

        if len(data['items']) < 100:
            break

        page += 1

    print(f"Purchases in last {days} days: {len(all_purchases)}")
    return all_purchases

# Get purchases from last 30 days
recent = get_recent_purchases(30)
```

### Get Purchases with Errors

Identify and review purchases that failed processing:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_error_purchases():
    """Get purchases with errors for review"""

    response = requests.get(
        "https://api.dcycle.io/api/v1/purchases",
        headers=headers,
        params={
            "filter_by": "status:eqerror",
            "page": 1,
            "size": 100
        }
    )

    purchases = response.json()

    print(f"⚠️ Purchases with errors: {len(purchases['items'])}")

    for purchase in purchases['items']:
        print(f"\nPurchase ID: {purchase['id']}")
        print(f"  Product: {purchase['product_name']}")
        print(f"  Sector: {purchase['sector']}")
        print(f"  Date: {purchase['purchase_date']}")
        print(f"  Status: {purchase['status']}")

    return purchases

# Review error purchases
errors = get_error_purchases()
```

### Analyze Emissions by Sector

Group purchases and calculate emissions by sector:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def analyze_emissions_by_sector():
    """Analyze total emissions grouped by sector"""

    # Get all active purchases
    all_purchases = []
    page = 1

    while True:
        response = requests.get(
            "https://api.dcycle.io/api/v1/purchases",
            headers=headers,
            params={
                "page": page,
                "size": 100,
                "filter_by": "status:active"
            }
        )

        data = response.json()
        all_purchases.extend(data['items'])

        if len(all_purchases) >= data['total']:
            break

        page += 1

    # Group by sector
    sectors = {}
    for purchase in all_purchases:
        sector = purchase['sector']
        if sector not in sectors:
            sectors[sector] = {
                'count': 0,
                'total_co2e': 0,
                'total_spend': 0
            }

        sectors[sector]['count'] += 1
        sectors[sector]['total_co2e'] += purchase['co2e'] or 0

        if purchase['unit']['type'] == 'fiat_currency':
            sectors[sector]['total_spend'] += purchase['quantity']

    # Sort by emissions
    sorted_sectors = sorted(
        sectors.items(),
        key=lambda x: x[1]['total_co2e'],
        reverse=True
    )

    print("Emissions by Sector:")
    print("-" * 70)
    for sector, data in sorted_sectors:
        print(f"{sector}:")
        print(f"  Purchases: {data['count']}")
        print(f"  Emissions: {data['total_co2e']:.2f} kg CO2e")
        print(f"  Spend: {data['total_spend']:.2f} EUR")
        print()

    return sorted_sectors

# Analyze emissions
analysis = analyze_emissions_by_sector()
```

## Purchase Types

### Spend-Based Purchases

**Description:** Emissions calculated based on monetary spend using economic input-output emission factors.

**Characteristics:**

* Most common method (80-90% of purchases)
* Requires: quantity (in currency), sector, country
* Uses standardized emission factors per EUR/USD spent
* Less accurate but practical for most purchases

**Example:** €25,000 spent on IT services

### Supplier-Specific Purchases

**Description:** Emissions calculated using supplier-provided product-specific emission factors.

**Characteristics:**

* More accurate than spend-based
* Requires: product name, supplier, specific emission factor
* Used when supplier provides LCA data
* Ideal for major suppliers or critical products

**Example:** 1000 kg of supplier-certified sustainable paper

## Expense Types

| Type            | Description                              | Scope 3 Category                |
| --------------- | ---------------------------------------- | ------------------------------- |
| `goods`         | Physical products                        | Category 1 - Purchased Goods    |
| `services`      | Professional and technical services      | Category 1 - Purchased Services |
| `capital_goods` | Long-lived assets (machinery, buildings) | Category 2 - Capital Goods      |
| `other`         | Miscellaneous purchases                  | Category 1                      |

## Frequency Options

Recurring purchases can be tracked with frequency:

| Frequency   | Description         |
| ----------- | ------------------- |
| `once`      | One-time purchase   |
| `weekly`    | Weekly recurring    |
| `monthly`   | Monthly recurring   |
| `quarterly` | Quarterly recurring |
| `yearly`    | Annual recurring    |

## Best Practices

### 1. Use Pagination Effectively

When you have many purchases, use pagination:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Good - Paginate through results
def get_all_purchases():
    all_purchases = []
    page = 1

    while True:
        response = requests.get(
            "https://api.dcycle.io/api/v1/purchases",
            headers=headers,
            params={"page": page, "size": 100}
        )

        data = response.json()
        all_purchases.extend(data['items'])

        if len(all_purchases) >= data['total']:
            break

        page += 1

    return all_purchases
```

### 2. Filter for Performance

Use server-side filtering instead of loading everything:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Good - Server-side filtering
response = requests.get(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    params={"filter_by": "sector:eqIT Services"}
)

# Bad - Client-side filtering
response = requests.get("https://api.dcycle.io/api/v1/purchases", headers=headers)
it_purchases = [p for p in response.json()['items'] if p['sector'] == 'IT Services']
```

### 3. Monitor Error Status

Regularly check for purchases with errors:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Check error count
response = requests.get(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    params={"page": 1, "size": 1}
)

error_count = response.json()['total2']
if error_count > 0:
    print(f"⚠️ {error_count} purchases need attention")
```

### 4. Sort by Emissions

Focus on high-impact purchases first:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Get top 20 emission sources
response = requests.get(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    params={
        "sort_by": "co2e:desc",
        "page": 1,
        "size": 20
    }
)

top_emitters = response.json()['items']
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Bulk Upload Purchases" icon="upload" href="/api-docs/purchases/bulk-upload">
    Upload multiple purchases via CSV
  </Card>

  <Card title="List Units" icon="ruler" href="/api-docs/units/list">
    Get measurement units for purchases
  </Card>

  <Card title="List Facilities" icon="building" href="/api-docs/facilities/list">
    View your facilities
  </Card>

  <Card title="Authentication" icon="key" href="/api-docs/authentication">
    Learn about API authentication
  </Card>
</CardGroup>
