> ## 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

> Retrieve all purchases with filtering and pagination support

# List Purchases

Retrieve a paginated list of purchases in your organization with support for filtering by status, type, expense type, date range, supplier, CO2e calculation status, and more.

## 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:** `a8315ef3-dd50-43f8-b7ce-d839e68d51fa`
</ParamField>

### Query Parameters

<ParamField query="status[]" type="array[string]">
  Filter by purchase status

  **Available values:** `active`, `pending`, `in_progress`, `in_review`, `inactive`, `error`

  **Example:** `status[]=active&status[]=pending`
</ParamField>

<ParamField query="purchase_type[]" type="array[string]">
  Filter by purchase calculation type

  **Available values:** `spend_based`, `supplier_specific`

  **Example:** `purchase_type[]=spend_based`
</ParamField>

<ParamField query="expense_type[]" type="array[string]">
  Filter by expense classification

  **Available values:** `capex`, `opex`

  **Example:** `expense_type[]=opex`
</ParamField>

<ParamField query="file_id[]" type="array[string]">
  Filter by linked file ID (UUID)

  **Example:** `file_id[]=550e8400-e29b-41d4-a716-446655440000`
</ParamField>

<ParamField query="search" type="string">
  Search by description or supplier name (case-insensitive substring match)

  **Example:** `office supplies`
</ParamField>

<ParamField query="description" type="string">
  Filter by purchase description (substring match)
</ParamField>

<ParamField query="supplier_id[]" type="array[string]">
  Filter by supplier UUID

  **Example:** `supplier_id[]=550e8400-e29b-41d4-a716-446655440000`
</ParamField>

<ParamField query="unit_id[]" type="array[string]">
  Filter by currency/unit UUID

  **Example:** `unit_id[]=eur-unit-uuid`
</ParamField>

<ParamField query="purchase_date_from" type="date">
  Filter purchases with `purchase_date` on or after this date (inclusive)

  **Example:** `2024-01-01`
</ParamField>

<ParamField query="purchase_date_to" type="date">
  Filter purchases with `purchase_date` on or before this date (inclusive)

  **Example:** `2024-12-31`
</ParamField>

<ParamField query="created_at_from" type="date">
  Filter purchases created on or after this date (inclusive)

  **Example:** `2024-01-01`
</ParamField>

<ParamField query="created_at_to" type="date">
  Filter purchases created on or before this date (inclusive)

  **Example:** `2024-12-31`
</ParamField>

<ParamField query="co2e_status" type="string">
  Filter by CO2e calculation status

  **Available values:** `calculated`, `not_calculated`
</ParamField>

<ParamField query="sort" type="string">
  Sort field. Prefix with `-` for descending order.

  **Available values:** `purchase_date`, `created_at`, `description`, `quantity`, `expense_type`, `status`, `product_name`, `sector`, `country`, `recycled`, `file_name`, `co2e`

  **Examples:** `co2e`, `-quantity`, `-purchase_date`
</ParamField>

<ParamField query="filter_by" type="string">
  Advanced per-column filter expression. Each clause is `field:operatorValue`, and multiple clauses are separated by `$`.

  **Operators:** `gt` (greater than), `lt` (less than), `gte` (≥), `lte` (≤), `bt[min,max]` (between), `eq` (equals), `neq` (not equals), `contains` (substring match)

  **Example:** `quantity:gt100$co2e:bt[10,500]` — quantity > 100 AND CO2e between 10 and 500
</ParamField>

<ParamField query="filter_match" type="string">
  How to combine `filter_by` clauses across different fields. Default combines with AND.

  **Available values:** `any` (OR — matches if any clause is true), `all` (AND — all clauses must match)

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

<ParamField query="filter_or_fields" type="string">
  Comma-separated list of field names whose same-field `filter_by` clauses should combine with OR instead of AND.

  **Example:** `status,expense_type` — multiple status or expense\_type filters use OR logic
</ParamField>

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

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

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

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

## Response

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

  <Expandable title="Purchase Object">
    <ResponseField name="id" type="string">
      Unique identifier (UUID)
    </ResponseField>

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

    <ResponseField name="product_name" type="string | null">
      Name of the product or service
    </ResponseField>

    <ResponseField name="description" type="string | null">
      Optional description
    </ResponseField>

    <ResponseField name="sector" type="string | null">
      Economic sector
    </ResponseField>

    <ResponseField name="country" type="string | null">
      2-letter ISO country code
    </ResponseField>

    <ResponseField name="quantity" type="number | null">
      Purchase amount
    </ResponseField>

    <ResponseField name="unit_id" type="string | null">
      Unit of measurement
    </ResponseField>

    <ResponseField name="purchase_date" type="date | null">
      Date of purchase
    </ResponseField>

    <ResponseField name="purchase_type" type="string | null">
      Calculation method: `spend_based` or `supplier_specific`
    </ResponseField>

    <ResponseField name="expense_type" type="string">
      Classification: `capex` or `opex`
    </ResponseField>

    <ResponseField name="status" type="string | null">
      Purchase status
    </ResponseField>

    <ResponseField name="recycled" type="number | null">
      Recycled content percentage (0-1)
    </ResponseField>

    <ResponseField name="supplier_id" type="string | null">
      Supplier identifier
    </ResponseField>

    <ResponseField name="custom_emission_factor_id" type="string | null">
      Custom emission factor UUID
    </ResponseField>

    <ResponseField name="file_id" type="string | null">
      Linked file UUID
    </ResponseField>

    <ResponseField name="file_name" type="string | null">
      Linked file name
    </ResponseField>

    <ResponseField name="file_url" type="string | null">
      Linked file download URL
    </ResponseField>

    <ResponseField name="co2e" type="number | null">
      Calculated CO2 equivalent emissions (kg)
    </ResponseField>

    <ResponseField name="frequency" type="string | null">
      Purchase frequency
    </ResponseField>

    <ResponseField name="exchange_rate_to_eur" type="number | null">
      Exchange rate used to convert the purchase amount to EUR
    </ResponseField>

    <ResponseField name="exchange_rate_date" type="date | null">
      Date used for the exchange rate lookup
    </ResponseField>

    <ResponseField name="custom_emission_group" type="object | null">
      Custom emission group applied to this purchase
    </ResponseField>

    <ResponseField name="last_purchase_timestamp" type="datetime | null">
      Timestamp of the most recent purchase in a recurring series
    </ResponseField>

    <ResponseField name="supplier" type="object | null">
      Supplier details (id, business\_name, country, enabled)
    </ResponseField>

    <ResponseField name="unit" type="object | null">
      Unit of measurement details
    </ResponseField>

    <ResponseField name="uploaded_by" type="string | null">
      UUID of the user who created this record
    </ResponseField>

    <ResponseField name="uploaded_by_user" type="object | null">
      User who created this record (id, first\_name, last\_name, email, profile\_img\_url)
    </ResponseField>

    <ResponseField name="created_at" type="datetime">
      Timestamp when the purchase was created
    </ResponseField>

    <ResponseField name="updated_at" type="datetime | null">
      Timestamp when the purchase was last updated
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="total" type="integer">
  Total number of purchases matching the filter
</ResponseField>

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

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

<ResponseField name="filter_hash" type="string">
  16-character hex hash of the applied filters. Pass this to the [bulk delete by filters](/api-reference/purchases/bulk-delete-by-filters) endpoint to ensure consistency.
</ResponseField>

## Example

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X GET "https://api.dcycle.io/v1/purchases?page=1&size=50&status[]=active" \
    -H "x-api-key: ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_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")

  headers = {
      "x-api-key": api_key,
      "x-organization-id": org_id
  }

  params = {
      "page": 1,
      "size": 50,
      "status[]": ["active"]
  }

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

  result = response.json()
  for purchase in result["items"]:
      print(f"{purchase['product_name']}: {purchase['co2e']} kg CO2e")
  ```

  ```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 headers = {
    'x-api-key': apiKey,
    'x-organization-id': orgId
  };

  const params = {
    page: 1,
    size: 50,
    'status[]': ['active']
  };

  axios.get(
    'https://api.dcycle.io/v1/purchases',
    { headers, params }
  )
  .then(response => {
    response.data.items.forEach(purchase => {
      console.log(`${purchase.product_name}: ${purchase.co2e} kg CO2e`);
    });
  })
  .catch(error => console.error(error));
  ```
</CodeGroup>

### Successful Response

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
      "product_name": "Office Supplies",
      "description": "Q1 2024 office supplies order",
      "sector": "Manufacturing",
      "country": "ES",
      "quantity": 1500.00,
      "unit_id": "EUR",
      "purchase_date": "2024-03-15",
      "purchase_type": "spend_based",
      "expense_type": "opex",
      "status": "active",
      "recycled": 0.25,
      "supplier_id": "supplier-123",
      "custom_emission_factor_id": null,
      "file_id": "660e8400-e29b-41d4-a716-446655440000",
      "file_name": "invoice_q1_2024.pdf",
      "file_url": "https://storage.dcycle.io/...",
      "co2e": 245.5,
      "frequency": "once",
      "exchange_rate_to_eur": 1.0,
      "exchange_rate_date": "2024-03-15",
      "custom_emission_group": null,
      "last_purchase_timestamp": null,
      "supplier": {
        "id": "supplier-123",
        "business_name": "Office Depot",
        "country": "ES",
        "enabled": true
      },
      "unit": { "id": "unit-uuid", "name": "EUR", "type": "currency" },
      "uploaded_by": null,
      "uploaded_by_user": null,
      "created_at": "2024-03-15T10:30:00Z",
      "updated_at": "2024-03-15T10:30:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
      "product_name": "Cloud Services",
      "description": "AWS hosting services",
      "sector": "Information and communication",
      "country": "US",
      "quantity": 5000.00,
      "unit_id": "USD",
      "purchase_date": "2024-03-01",
      "purchase_type": "spend_based",
      "expense_type": "opex",
      "status": "active",
      "recycled": null,
      "supplier_id": "aws-123",
      "custom_emission_factor_id": null,
      "file_id": null,
      "file_name": null,
      "file_url": null,
      "co2e": 892.3,
      "frequency": "once",
      "exchange_rate_to_eur": 0.92,
      "exchange_rate_date": "2024-03-01",
      "custom_emission_group": null,
      "last_purchase_timestamp": null,
      "supplier": null,
      "unit": { "id": "unit-uuid", "name": "USD", "type": "currency" },
      "uploaded_by": null,
      "uploaded_by_user": null,
      "created_at": "2024-03-01T09:00:00Z",
      "updated_at": "2024-03-01T09:00:00Z"
    }
  ],
  "total": 156,
  "page": 1,
  "size": 50,
  "filter_hash": "a1b2c3d4e5f67890"
}
```

## Common Errors

### 401 Unauthorized

**Cause:** Missing or invalid API key

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "Invalid API key",
  "code": "INVALID_API_KEY"
}
```

**Solution:** Verify your API key is valid and active. Get a new one from [Settings -> API](https://app.dcycle.io/settings/api).

### 404 Not Found

**Cause:** Organization not found

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "code": "ORGANIZATION_NOT_FOUND",
  "detail": "Organization with id=UUID('...') not found"
}
```

**Solution:** Verify that the `x-organization-id` header contains a valid organization UUID.

### 422 Validation Error

**Cause:** Invalid query parameters

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": [
    {
      "loc": ["query", "size"],
      "msg": "ensure this value is less than or equal to 100",
      "type": "value_error.number.not_le"
    }
  ]
}
```

**Solution:** Check that page size is between 1 and 100, and that filter values are valid enums.

## Use Cases

### Get All Active Purchases

Retrieve only active purchases:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_active_purchases():
    """Get all active purchases in the organization"""
    response = requests.get(
        "https://api.dcycle.io/v1/purchases",
        headers=headers,
        params={"status[]": ["active"], "size": 100}
    )
    return response.json()["items"]

active_purchases = get_active_purchases()
print(f"Active purchases: {len(active_purchases)}")
```

### Filter by Expense Type

Get only operational expenditures:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_opex_purchases():
    """Get all OPEX purchases (Scope 3 Category 1)"""
    response = requests.get(
        "https://api.dcycle.io/v1/purchases",
        headers=headers,
        params={
            "expense_type[]": ["opex"],
            "status[]": ["active"],
            "size": 100
        }
    )
    return response.json()["items"]

opex = get_opex_purchases()
total_opex_co2e = sum(p.get("co2e", 0) for p in opex)
print(f"OPEX emissions: {total_opex_co2e} kg CO2e")
```

### Calculate Category 1 Totals

Sum up all purchased goods and services emissions:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def get_category_1_total():
    """Calculate total Scope 3 Category 1 emissions"""
    total_co2e = 0
    page = 1

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

        for purchase in data["items"]:
            total_co2e += purchase.get("co2e", 0) or 0

        if len(data["items"]) < 100:
            break
        page += 1

    return total_co2e

total = get_category_1_total()
print(f"Scope 3 Category 1: {total:,.0f} kg CO2e ({total/1000:.1f} tonnes)")
```

### Group by Sector

Analyze purchases by economic sector:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from collections import defaultdict

def get_purchases_by_sector():
    """Group purchases by sector"""
    sector_totals = defaultdict(float)
    page = 1

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

        for purchase in data["items"]:
            sector = purchase.get("sector") or "Unknown"
            sector_totals[sector] += purchase.get("co2e", 0) or 0

        if len(data["items"]) < 100:
            break
        page += 1

    return dict(sector_totals)

by_sector = get_purchases_by_sector()
for sector, co2e in sorted(by_sector.items(), key=lambda x: -x[1]):
    print(f"{sector}: {co2e:,.0f} kg CO2e")
```

## Pagination Guide

Navigate through large purchase lists efficiently:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def iterate_all_purchases(batch_size=50):
    """Iterate through all purchases in organization"""
    page = 1
    while True:
        response = requests.get(
            "https://api.dcycle.io/v1/purchases",
            headers=headers,
            params={"page": page, "size": batch_size}
        )
        data = response.json()

        for purchase in data["items"]:
            yield purchase

        if len(data["items"]) < batch_size:
            break
        page += 1

# Process all purchases
for purchase in iterate_all_purchases():
    print(f"Processing {purchase['product_name']}")
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Get Purchase" icon="receipt" href="/api-reference/purchases/get">
    Get a specific purchase by ID
  </Card>

  <Card title="Create Purchase" icon="plus" href="/api-reference/purchases/create">
    Add a new purchase to your organization
  </Card>

  <Card title="Update Purchase" icon="pencil" href="/api-reference/purchases/update">
    Modify purchase details
  </Card>

  <Card title="Delete Purchase" icon="trash" href="/api-reference/purchases/delete">
    Remove a purchase
  </Card>
</CardGroup>
