curl -X POST "https://api.dcycle.io/v2/logistic-hubs" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"client_row_id": "HUB-001"
},
{
"name": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/logistic-hubs",
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": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona",
}
]
},
timeout=60,
)
response.raise_for_status()
for item in response.json()["items"]:
print(item["hub"]["name"], item["hub"]["id"])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"hub": {
"id": "4f3e2d1c-0b9a-4876-9543-210fedcba987",
"organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"supercharger": false,
"status": "active",
"created_at": "2026-10-20T09:12:44.031Z",
"updated_at": "2026-10-20T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"error_code": "HUB_NAME_ALREADY_EXISTS",
"error_params": { "field": "name", "value": "MAD-01" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
Create Logistic Hubs (v2)
Create up to 1,000 logistic hubs in one request and get them back
POST
/
v2
/
logistic-hubs
curl -X POST "https://api.dcycle.io/v2/logistic-hubs" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"client_row_id": "HUB-001"
},
{
"name": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/logistic-hubs",
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": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona",
}
]
},
timeout=60,
)
response.raise_for_status()
for item in response.json()["items"]:
print(item["hub"]["name"], item["hub"]["id"])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"hub": {
"id": "4f3e2d1c-0b9a-4876-9543-210fedcba987",
"organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"supercharger": false,
"status": "active",
"created_at": "2026-10-20T09:12:44.031Z",
"updated_at": "2026-10-20T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"error_code": "HUB_NAME_ALREADY_EXISTS",
"error_params": { "field": "name", "value": "MAD-01" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
← Logistic Hubs API
Create one or many logistic hubs: your warehouses, cross-docks and transshipment points, and the third-party ones your
shipments go through. A hub is master data: creating it calculates nothing (an owned hub’s emissions are those of its
facility), so the request is synchronous: it answers
201 Created with every
hub, in the order you sent them. Create your hubs before the logistics requests that reference them.
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/logistic-hubs" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"client_row_id": "HUB-001"
},
{
"name": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/logistic-hubs",
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": "PART-BCN",
"type": "subcontracted",
"country": "ES",
"address": "Carrer del Port 3, 08039 Barcelona",
}
]
},
timeout=60,
)
response.raise_for_status()
for item in response.json()["items"]:
print(item["hub"]["name"], item["hub"]["id"])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"hub": {
"id": "4f3e2d1c-0b9a-4876-9543-210fedcba987",
"organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
"name": "MAD-01",
"type": "owned",
"country": "ES",
"address": "Calle de la Logística 12, 28042 Madrid",
"category": "warehouse_ambient",
"facility_id": "c2a8f6b4-3e1d-4f7a-9b2c-5d6e7f8a9b0c",
"supercharger": false,
"status": "active",
"created_at": "2026-10-20T09:12:44.031Z",
"updated_at": "2026-10-20T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "HUB-001",
"error_code": "HUB_NAME_ALREADY_EXISTS",
"error_params": { "field": "name", "value": "MAD-01" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
How it works
- Every record is checked: the name is free, the country and the category exist, and an owned hub’s facility is
usable and not already linked to another hub. If any record is invalid the whole request is rejected with
422and nothing is created; the answer lists every invalid record. - Every hub is created in one transaction and returned, in the order sent.
source_row_indexis the position of the record inrecords, andclient_row_idechoes yours. - The address is stored as you send it; it is not geocoded here. Logistics requests that reference the hub take it as their origin and geocode it when they are calculated: an address that cannot be located shows up then, as a per-leg error of those requests. Send the full address (street, postal code, city).
- The hubs belong to the
x-organization-idorganization. A record cannot name another one: send each organization’s hubs with its ownx-organization-id. - Logistics requests find a hub by its exact
name(thehub_idof Create Logistics Requests (v2)): same case, no extra spaces. Use the code your own systems use for it.
Request
Headers
string
required
Your API key (see Authentication).
string
required
The organization the hubs belong to.
string
required
1 to 255 characters, unique per batch. A retry with the same key and body answers the same hubs (with
Idempotent-Replayed: true) instead of creating them again; the same key with another body is
422 IDEMPOTENCY_KEY_REUSED, and while the first request is still being processed
409 IDEMPOTENCY_KEY_IN_PROGRESS.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 hubs to create, 1 to 1,000. A field not listed here is rejected (
SCHEMA_INVALID).Show record
Show record
string
required
1 to 255 characters, stored trimmed: the hub’s code, as your logistics requests send it in
hub_id. It must be
free in the organization (archived hubs included) and appear once in the request.string
required
owned (a hub your organization runs: give its facility_id) or subcontracted (run by a third party).string
required
Where the hub is, ISO 3166-1 alpha-2 (
ES, FR…; case-insensitive, returned uppercase).string
required
1 to 500 characters, stored trimmed and not geocoded. Logistics requests that reference the hub use it as their
origin.
string
default:"transshipment_ambient"
The hub operation: a
category of List HOCs (transshipment_ambient,
warehouse_mixed, storage_transhipment_ambient…).uuid
Required for
owned, not allowed for subcontracted: the facility the hub is,
of your organization or of a subsidiary you can write to, enabled and not archived. One hub per facility: a
facility already linked to another hub, or sent twice, is rejected. An owned hub’s emissions are its
facility’s.boolean
default:"false"
Whether the hub is an electric charging point.
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 hub: id, organization_id, name, type, country, address, category, facility_id,
supercharger, status (active) and 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: a missing or unknown field (e.g. organization_id), a type other than owned/subcontracted, an empty address, a country that is not two letters… error_params.errors says where. |
HUB_NAME_ALREADY_EXISTS | A hub of the organization (archived ones included) already has this name. |
DUPLICATE_HUB_NAME | Another record of the request has the same name. |
REFERENCE_NOT_FOUND | country or category does not exist, or facility_id does not exist, is disabled or archived, or is outside your organization and the subsidiaries you can write to (all answer the same; error_params.field says which field). |
FACILITY_ALREADY_LINKED_TO_HUB | facility_id is already the facility of another hub, or appears in two records of the request. |
FACILITY_REQUIRED_FOR_OWNED_HUB | An owned hub without facility_id. |
FACILITY_NOT_ALLOWED_FOR_SUBCONTRACTED_HUB | A subcontracted hub with facility_id. |
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, 409 IDEMPOTENCY_KEY_IN_PROGRESS, and 429 beyond the
rate limits.
Retries and idempotency
- Network error or timeout: retry with the same
Idempotency-Keyand body. If the first request was accepted you get the same hubs 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
List Logistic Hubs
The organization’s hubs and their ids
List HOCs
Values for
categoryList Facilities
Ids for
facility_idCreate Logistics Requests (v2)
The shipment legs that reference your hubs
Was this page helpful?