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"}
]
}'
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"])
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));
{
"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",
"...": "..."
}
}
]
}
{
"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"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
Create Facilities (v2)
Create up to 1,000 facilities in one request and get them back
POST
/
v2
/
facilities
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"}
]
}'
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"])
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));
{
"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",
"...": "..."
}
}
]
}
{
"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"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
← Facilities API
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.
Beta. Part of the bulk ingest API, currently in beta. The contract may still change before general availability.
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"}
]
}'
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"])
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));
{
"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",
"...": "..."
}
}
]
}
{
"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"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
How it works
- Every record is checked. If any is invalid the whole request is rejected with
422and nothing is created; the answer lists every invalid record, so you can fix them all at once. - Every facility is created in one transaction and returned, in the order sent.
source_row_indexis the position of the record inrecords, andclient_row_idechoes yours. countrydecides where the facility is. It is required and stored as sent.addressis optional and only informative: it is not geocoded (unlikePOST /v1/facilities, which replaced the country with the one Google found for the address).
Request
Headers
string
required
Your API key for authenticationExample:
sk_live_1234567890abcdefstring
required
Your organization UUIDExample:
a8315ef3-dd50-43f8-b7ce-d839e68d51fastring
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.Query Parameters
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.Body Parameters
array[object]
required
The facilities to create, 1 to 1,000.
Show record
Show record
string
required
1 to 255 characters. Example:
"Madrid Office"string
required
ISO 3166-1 alpha-2 code, uppercase. Example:
"ES", "FR", "US"string
required
Ownership of the site:
owned or rented.string
Up to 500 characters. Stored as sent, never geocoded.
array[string]
Data the facility collects: any of
electricity, heat, water, recharge, wastes, process. Omitted:
heat, electricity, water and recharge.number
default:"0.8"
Between 0 and 1.
array[string]
Electricity supply point codes (CUPS) of the facility.
number
0 or more, in
surface_area_unit.string
m2, ft2 or ha.uuid
The organization that owns the facility. Omitted: the one in
x-organization-id. It may also be one of its
accepted subsidiaries.string
Your own reference for the record, up to 255 characters, echoed in the answer and in errors.
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, with UTC timestamps ending in Z).
Errors
Problem details. Per-record codes inerrors[].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-Keyand body. If the first request was accepted you get the same facilities back, withIdempotent-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
Delete Facilities (v2)
Delete up to 1,000 facilities with their data
Create Wastes (v2)
Load wastes into the new facilities
Was this page helpful?