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

# Create Facilities (v2)

> Create up to 1,000 facilities in one request and get them back

[← Facilities API](/api-reference/facilities/overview)

Create one or many facilities. Creating a facility calculates nothing, so the request is **synchronous**: it answers
`201 Created` with every facility, in the order you sent them, ready to use as `facility_id` in your consumption data.

<Warning>
  **Beta.** Part of the bulk ingest API, currently in beta. The contract may still change before general availability.
</Warning>

<RequestExample>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST "https://api.dcycle.io/v2/facilities" \
    -H "x-api-key: ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_ID}" \
    -H "Idempotency-Key: 5d1e2f3a-4b5c-4d6e-8f70-81a2b3c4d5e6" \
    -H "Content-Type: application/json" \
    -d '{
      "records": [
        {"name": "Madrid Office", "country": "ES", "type": "rented", "categories": ["electricity", "heat"], "client_row_id": "SITE-001"},
        {"name": "Lyon Warehouse", "country": "FR", "type": "owned", "address": "12 Rue de la République, Lyon", "surface_area": 3200, "surface_area_unit": "m2"}
      ]
    }'
  ```

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

  import requests

  response = requests.post(
      "https://api.dcycle.io/v2/facilities",
      headers={
          "x-api-key": os.environ["DCYCLE_API_KEY"],
          "x-organization-id": os.environ["DCYCLE_ORG_ID"],
          "Idempotency-Key": str(uuid.uuid4()),  # keep it to retry this same batch
      },
      json={
          "records": [
              {"name": "Madrid Office", "country": "ES", "type": "rented", "client_row_id": "SITE-001"},
              {"name": "Lyon Warehouse", "country": "FR", "type": "owned"},
          ]
      },
      timeout=60,
  )
  response.raise_for_status()
  for item in response.json()["items"]:
      print(item["client_row_id"], item["facility"]["id"])
  ```

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

  const { data } = await axios.post(
    'https://api.dcycle.io/v2/facilities',
    {
      records: [
        { name: 'Madrid Office', country: 'ES', type: 'rented', client_row_id: 'SITE-001' },
        { name: 'Lyon Warehouse', country: 'FR', type: 'owned' },
      ],
    },
    {
      headers: {
        'x-api-key': process.env.DCYCLE_API_KEY,
        'x-organization-id': process.env.DCYCLE_ORG_ID,
        'Idempotency-Key': randomUUID(), // keep it to retry this same batch
      },
    },
  );
  data.items.forEach((item) => console.log(item.client_row_id, item.facility.id));
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "items": [
      {
        "source_row_index": 0,
        "client_row_id": "SITE-001",
        "facility": {
          "id": "0b8e4d2a-1c3f-4e5a-9b7d-6c8e0f2a4b6d",
          "organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
          "name": "Madrid Office",
          "address": null,
          "country": "ES",
          "type": "rented",
          "categories": ["electricity", "heat"],
          "cups_list": null,
          "status": "active",
          "logistic_factor": 0.8,
          "surface_area": null,
          "surface_area_unit": null,
          "facility_purpose_type": "facilities",
          "created_at": "2026-10-07T09:12:44.381Z",
          "updated_at": "2026-10-07T09:12:44.381Z"
        }
      },
      {
        "source_row_index": 1,
        "client_row_id": null,
        "facility": {
          "id": "7f6e5d4c-3b2a-4190-8e7f-6d5c4b3a2918",
          "name": "Lyon Warehouse",
          "country": "FR",
          "type": "owned",
          "...": "..."
        }
      }
    ]
  }
  ```

  ```json 422 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
    "title": "Unprocessable Content",
    "status": 422,
    "code": "BULK_RECORDS_REJECTED",
    "detail": "1 of the submitted records are invalid; nothing was written.",
    "errors": [
      {
        "source_row_index": 1,
        "client_row_id": null,
        "error_code": "REFERENCE_NOT_FOUND",
        "error_params": { "field": "country", "value": "UK" }
      }
    ],
    "rejected": 1,
    "request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
  }
  ```

  ```json 200 (dry_run=true) theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "dry_run": true, "submitted": 2, "valid": 2 }
  ```
</ResponseExample>

## How it works

1. **Every record is checked.** If any is invalid the **whole** request is rejected with `422` and nothing is
   created; the answer lists every invalid record, so you can fix them all at once.
2. **Every facility is created in one transaction** and returned, in the order sent. `source_row_index` is the
   position of the record in `records`, and `client_row_id` echoes yours.
3. **`country` decides where the facility is.** It is required and stored as sent. `address` is optional and only
   informative: it is **not** geocoded (unlike `POST /v1/facilities`, which replaced the country with the one Google
   found for the address).

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

<ParamField header="Idempotency-Key" type="string" required>
  1 to 255 characters, unique per batch. A retry with the same key and body answers the same facilities (with
  `Idempotent-Replayed: true`) instead of creating them again; the same key with another body is
  `422 IDEMPOTENCY_KEY_REUSED`.
</ParamField>

### Query Parameters

<ParamField query="dry_run" type="boolean" default="false">
  Check only: the same `422` for invalid records, nothing created; `200` with `{"dry_run": true, "submitted": n,
      "valid": n}` when every record is valid.
</ParamField>

### Body Parameters

<ParamField body="records" type="array[object]" required>
  The facilities to create, 1 to 1,000.

  <Expandable title="record">
    <ParamField body="name" type="string" required>
      1 to 255 characters. **Example:** `"Madrid Office"`
    </ParamField>

    <ParamField body="country" type="string" required>
      ISO 3166-1 alpha-2 code, uppercase. **Example:** `"ES"`, `"FR"`, `"US"`
    </ParamField>

    <ParamField body="type" type="string" required>
      Ownership of the site: `owned` or `rented`.
    </ParamField>

    <ParamField body="address" type="string">
      Up to 500 characters. Stored as sent, never geocoded.
    </ParamField>

    <ParamField body="categories" type="array[string]">
      Data the facility collects: any of `electricity`, `heat`, `water`, `recharge`, `wastes`, `process`. Omitted:
      `heat`, `electricity`, `water` and `recharge`.
    </ParamField>

    <ParamField body="logistic_factor" type="number" default="0.8">
      Between 0 and 1.
    </ParamField>

    <ParamField body="cups_list" type="array[string]">
      Electricity supply point codes (CUPS) of the facility.
    </ParamField>

    <ParamField body="surface_area" type="number">
      0 or more, in `surface_area_unit`.
    </ParamField>

    <ParamField body="surface_area_unit" type="string">
      `m2`, `ft2` or `ha`.
    </ParamField>

    <ParamField body="organization_id" type="uuid">
      The organization that owns the facility. Omitted: the one in `x-organization-id`. It may also be one of its
      accepted subsidiaries.
    </ParamField>

    <ParamField body="client_row_id" type="string">
      Your own reference for the record, up to 255 characters, echoed in the answer and in errors.
    </ParamField>
  </Expandable>
</ParamField>

## Response

`201 Created` with `items`: one per record, in the order sent, each with `source_row_index`, `client_row_id` and the
created `facility` (the same object as [Get Facility](/api-reference/facilities/get), with UTC timestamps ending in `Z`).

## Errors

[Problem details](/api-reference/errors). Per-record codes in `errors[].error_code`:

| `error_code` | Cause |
| - | - |
| `SCHEMA_INVALID` | The record does not match the schema (missing `name`, `country` not two uppercase letters, unknown `type` or category...). `error_params.errors` says where. |
| `REFERENCE_NOT_FOUND` | `country` is two letters but not a country Dcycle knows (`error_params.field` is `country`). |
| `ORGANIZATION_NOT_FOUND` | `organization_id` does not exist or is not your organization nor one of its subsidiaries (both answer the same). |
| `FACILITY_LIMIT_REACHED` | The organization is on the free plan and this record would exceed its facility allowance (`error_params.limit`). |

`401` for a missing or invalid API key, `403 LOGGED_USER_NOT_MEMBER` when the key's user is not a member of the
organization, `422 REQUEST_VALIDATION_FAILED` for a malformed body (no `records`, more than 1,000, no
`Idempotency-Key`), `422 IDEMPOTENCY_KEY_REUSED` for a key already used with another body.

## Retries and idempotency

* **Network error or timeout:** retry with the **same** `Idempotency-Key` and body. If the first request was
  accepted you get the same facilities back, with `Idempotent-Replayed: true`, and nothing is duplicated.
* **`422 BULK_RECORDS_REJECTED`:** nothing was created. Fix the records and send the batch again.

## Limits

| Limit | Value |
| - | - |
| Records per request | 1 to 1,000 |

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Delete Facilities (v2)" icon="trash" href="/api-reference/facilities/delete-v2">
    Delete up to 1,000 facilities with their data
  </Card>

  <Card title="Create Wastes (v2)" icon="recycle" href="/api-reference/wastes/create-v2">
    Load wastes into the new facilities
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.