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

# Bulk Upload Waste Water Treatments

> Create waste water treatment records in bulk with automatic data imputation

# Bulk Upload Waste Water Treatments

Upload daily waste water treatment measurements in bulk for a waste water facility. This endpoint automatically imputes missing values using interpolation and moving averages.

<Warning>
  **Important Constraints:**

  * Maximum 31 days of data per request
  * The last entry must have complete data for all totalized fields
  * Missing values are automatically imputed
  * CH4 emissions cannot be negative
</Warning>

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

### Body Parameters

<ParamField body="facility_id" type="string" required>
  UUID of the waste water facility

  **Example:** `"facility-uuid-here"`
</ParamField>

<ParamField body="daily_waste_water_treatment_data" type="array" required>
  Array of daily measurement records (max 31 days)

  Each daily record contains:

  * `name` (string, required): Description of the data
  * `measurement_date` (date, required): Date of measurement (YYYY-MM-DD)
  * `m3_water_in` (float, optional): Input flow in m³
  * `m3_water_out` (float, optional): Output flow in m³
  * `kg_bod_per_m3_wwt_line` (float, optional): Input BOD in kg/m³
  * `kg_n_per_m3_wwt_line` (float, optional): Nitrogen in kg/m³ (treatment line)
  * `kg_sludge` (float, optional): Total evacuated sludge in kg
  * `st` (float, optional): Proportion of solids (0-1)
  * `m3_biogas_engine` (float, optional): Engine biogas in m³
  * `m3_biogas_flare` (float, optional): Flare biogas in m³
  * `m3_biogas_boiler` (float, optional): Boiler biogas in m³
  * `methane` (float, optional): Methane proportion (0-1)
  * `kg_bod_per_kg_sludge_line` (float, optional): BOD in sludge kg/kg
  * `kg_bod_per_m3_wwd_line` (float, optional): BOD in discharge kg/m³
  * `kg_n_per_m3_wwd_line` (float, optional): Nitrogen in discharge kg/m³
</ParamField>

<Note>
  **Last Entry Requirement:** The last entry in your data array must have non-null values for:

  * `m3_water_in`
  * `m3_water_out`
  * `kg_sludge`
  * `m3_biogas_engine`
  * `m3_biogas_flare`
  * `m3_biogas_boiler`
</Note>

## Response

Returns an array of created waste water treatment records with calculated emissions.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
[
  {
    "id": "treatment-uuid",
    "name": "Waste Water Treatment Data Line 1",
    "m3_water_in": 39245.33,
    "m3_water_out": 31859.12,
    "kg_sludge": 27140.0,
    "kg_bod_per_m3_wwt_line": 0.185,
    "kg_bod_per_kg_sludge_line": 0.012,
    "kg_n_per_m3_wwt_line": 0.0912,
    "kg_r_wwt_line": 2896.5,
    "file_url": null,
    "start_date": "2024-03-31",
    "end_date": "2024-03-31",
    "status": "uploaded",
    "uploaded_by": "user-uuid",
    "facility_id": "facility-uuid"
  }
]
```

## Example

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST "https://api.dcycle.io/api/v1/bulk/waste_water_treatments" \
    -H "Authorization: Bearer ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_ID}" \
    -H "x-user-id: ${DCYCLE_USER_ID}" \
    -H "Content-Type: application/json" \
    -d '{
      "facility_id": "facility-uuid",
      "daily_waste_water_treatment_data": [
        {
          "name": "Daily Treatment 2024-03-01",
          "measurement_date": "2024-03-01",
          "m3_water_in": 38000,
          "m3_water_out": 30000,
          "kg_bod_per_m3_wwt_line": 0.180,
          "kg_n_per_m3_wwt_line": 0.090,
          "kg_sludge": 25000,
          "st": 0.24,
          "m3_biogas_engine": 6000,
          "m3_biogas_flare": 1200,
          "m3_biogas_boiler": 60,
          "methane": 0.6,
          "kg_bod_per_kg_sludge_line": 0.012,
          "kg_bod_per_m3_wwd_line": 0.007,
          "kg_n_per_m3_wwd_line": 0.009
        },
        {
          "name": "Daily Treatment 2024-03-02",
          "measurement_date": "2024-03-02",
          "m3_water_in": 39000,
          "m3_water_out": 31000,
          "kg_bod_per_m3_wwt_line": 0.185,
          "kg_n_per_m3_wwt_line": 0.091,
          "kg_sludge": 26000,
          "st": 0.24,
          "m3_biogas_engine": 6100,
          "m3_biogas_flare": 1220,
          "m3_biogas_boiler": 65,
          "methane": 0.6,
          "kg_bod_per_kg_sludge_line": 0.012,
          "kg_bod_per_m3_wwd_line": 0.007,
          "kg_n_per_m3_wwd_line": 0.0091
        }
      ]
    }'
  ```

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

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

  facility_id = "facility-uuid"

  # Generate 7 days of data
  daily_data = []
  start_date = date(2024, 3, 1)

  for day in range(7):
      current_date = start_date + timedelta(days=day)
      daily_data.append({
          "name": f"Daily Treatment {current_date}",
          "measurement_date": current_date.isoformat(),
          "m3_water_in": 38000 + (day * 100),
          "m3_water_out": 30000 + (day * 80),
          "kg_bod_per_m3_wwt_line": 0.180,
          "kg_n_per_m3_wwt_line": 0.090,
          "kg_sludge": 25000 + (day * 200),
          "st": 0.24,
          "m3_biogas_engine": 6000,
          "m3_biogas_flare": 1200,
          "m3_biogas_boiler": 60,
          "methane": 0.6,
          "kg_bod_per_kg_sludge_line": 0.012,
          "kg_bod_per_m3_wwd_line": 0.007,
          "kg_n_per_m3_wwd_line": 0.009
      })

  request_data = {
      "facility_id": facility_id,
      "daily_waste_water_treatment_data": daily_data
  }

  response = requests.post(
      "https://api.dcycle.io/api/v1/bulk/waste_water_treatments",
      headers=headers,
      json=request_data
  )

  treatments = response.json()
  print(f"✅ Created {len(treatments)} waste water treatment records")

  for treatment in treatments:
      print(f"- {treatment['start_date']}: {treatment['m3_water_in']} m³ in, {treatment['m3_water_out']} m³ out")
  ```

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

  const headers = {
    'Authorization': `Bearer ${process.env.DCYCLE_API_KEY}`,
    'x-organization-id': process.env.DCYCLE_ORG_ID,
    'x-user-id': process.env.DCYCLE_USER_ID,
    'Content-Type': 'application/json'
  };

  const facilityId = 'facility-uuid';

  // Generate 7 days of data
  const dailyData = [];
  const startDate = new Date('2024-03-01');

  for (let day = 0; day < 7; day++) {
    const currentDate = new Date(startDate);
    currentDate.setDate(startDate.getDate() + day);

    dailyData.push({
      name: `Daily Treatment ${currentDate.toISOString().split('T')[0]}`,
      measurement_date: currentDate.toISOString().split('T')[0],
      m3_water_in: 38000 + (day * 100),
      m3_water_out: 30000 + (day * 80),
      kg_bod_per_m3_wwt_line: 0.180,
      kg_n_per_m3_wwt_line: 0.090,
      kg_sludge: 25000 + (day * 200),
      st: 0.24,
      m3_biogas_engine: 6000,
      m3_biogas_flare: 1200,
      m3_biogas_boiler: 60,
      methane: 0.6,
      kg_bod_per_kg_sludge_line: 0.012,
      kg_bod_per_m3_wwd_line: 0.007,
      kg_n_per_m3_wwd_line: 0.009
    });
  }

  const requestData = {
    facility_id: facilityId,
    daily_waste_water_treatment_data: dailyData
  };

  axios.post(
    'https://api.dcycle.io/api/v1/bulk/waste_water_treatments',
    requestData,
    { headers }
  )
  .then(response => {
    const treatments = response.data;
    console.log(`✅ Created ${treatments.length} waste water treatment records`);

    treatments.forEach(treatment => {
      console.log(`- ${treatment.start_date}: ${treatment.m3_water_in} m³ in, ${treatment.m3_water_out} m³ out`);
    });
  })
  .catch(error => console.error(error));
  ```
</CodeGroup>

## Data Imputation

The endpoint automatically fills missing values using these methods:

### Interpolation

Missing values are interpolated linearly between known values for:

* `m3_water_in`
* `m3_water_out`
* `kg_sludge`
* `m3_biogas_engine`
* `m3_biogas_flare`
* `m3_biogas_boiler`

### Moving Average

Missing values are filled with 6-period moving average (forward/backward fill) for:

* `kg_n_per_m3_wwt_line`
* `kg_bod_per_m3_wwt_line`
* `kg_bod_per_m3_wwd_line`
* `st` (solid proportion)
* `methane`
* `kg_bod_per_kg_sludge_line`
* `kg_n_per_m3_wwd_line`

<Info>
  You can submit partial data for intermediate days. The endpoint will automatically fill gaps, but the **last entry** must have complete totalized values.
</Info>

## Common Errors

### 400 Bad Request - Facility Not Found

**Cause:** FACILITY\_NOT\_FOUND

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "FACILITY_NOT_FOUND",
  "code": "BAD_REQUEST"
}
```

**Solution:** Verify the facility ID exists.

### 400 Bad Request - Maximum Rows Exceeded

**Cause:** MAXIMUM\_ROWS\_EXCEEDED

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "MAXIMUM_ROWS_EXCEEDED",
  "code": "BAD_REQUEST"
}
```

**Solution:** Date range between min and max measurement\_date must not exceed 31 days. Split into multiple requests if needed.

### 400 Bad Request - Null Values in Last Row

**Cause:** NULL\_VALUES\_IN\_LAST\_ROW

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "NULL_VALUES_IN_LAST_ROW",
  "code": "BAD_REQUEST"
}
```

**Solution:** Ensure the last entry has non-null values for all totalized fields: `m3_water_in`, `m3_water_out`, `kg_sludge`, `m3_biogas_engine`, `m3_biogas_flare`, `m3_biogas_boiler`.

### 400 Bad Request - Negative Value

**Cause:** NEGATIVE\_m3\_water\_in

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "detail": "NEGATIVE_m3_water_in",
  "code": "BAD_REQUEST"
}
```

**Solution:** All measurement values must be non-negative (≥ 0).

## Best Practices

### 1. Submit Complete Final Entry

Always ensure the last entry has all required fields:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# ✅ Good: Last entry is complete
daily_data = [
    {
        "measurement_date": "2024-03-01",
        "m3_water_in": None,  # Will be imputed
        "m3_water_out": None,  # Will be imputed
        # ... other fields
    },
    {
        "measurement_date": "2024-03-02",
        "m3_water_in": 39000,  # Complete
        "m3_water_out": 31000,  # Complete
        "kg_sludge": 26000,  # Complete
        "m3_biogas_engine": 6100,  # Complete
        "m3_biogas_flare": 1220,  # Complete
        "m3_biogas_boiler": 65,  # Complete
        # ... all required fields present
    }
]
```

### 2. Handle Date Ranges

Split large date ranges into multiple requests:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def upload_monthly_data(facility_id, monthly_data):
    # Split into chunks of max 31 days
    chunk_size = 30
    for i in range(0, len(monthly_data), chunk_size):
        chunk = monthly_data[i:i + chunk_size]

        response = requests.post(
            "https://api.dcycle.io/api/v1/bulk/waste_water_treatments",
            headers=headers,
            json={
                "facility_id": facility_id,
                "daily_waste_water_treatment_data": chunk
            }
        )

        print(f"Uploaded chunk {i//chunk_size + 1}: {len(chunk)} days")
```

### 3. Validate Before Upload

Check data quality before submitting:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def validate_wwt_data(data):
    # Check last entry completeness
    last_entry = data[-1]
    required_fields = ['m3_water_in', 'm3_water_out', 'kg_sludge',
                      'm3_biogas_engine', 'm3_biogas_flare', 'm3_biogas_boiler']

    for field in required_fields:
        if last_entry.get(field) is None:
            raise ValueError(f"Last entry missing required field: {field}")

    # Check date range
    dates = [entry['measurement_date'] for entry in data]
    date_range = (max(dates) - min(dates)).days + 1

    if date_range > 31:
        raise ValueError(f"Date range ({date_range} days) exceeds maximum of 31 days")

    return True

# Use before upload
if validate_wwt_data(daily_data):
    response = requests.post(url, headers=headers, json=request_data)
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Delete Treatment" icon="trash" href="/api-docs/waste-water-treatments/delete">
    Remove a treatment record
  </Card>

  <Card title="Facilities" icon="building" href="/api-docs/facilities/list">
    List waste water facilities
  </Card>
</CardGroup>
