Create Logistics Requests (Bulk, v2)
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'Content-Type': '<content-type>'
}
};
fetch('https://api.dcycle.io/v2/logistics/requests/bulk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v2/logistics/requests/bulk"
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"Content-Type": "<content-type>"
}
response = requests.post(url, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/v2/logistics/requests/bulk \
--header 'Content-Type: <content-type>' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>'{
"success": 123,
"failed": 123,
"results": [
{}
],
"errors": [
{}
]
}Create Logistics Requests (Bulk, v2)
Bulk-create logistics shipments with asynchronous emissions calculation and progress tracking
POST
/
v2
/
logistics
/
requests
/
bulk
Create Logistics Requests (Bulk, v2)
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'Content-Type': '<content-type>'
}
};
fetch('https://api.dcycle.io/v2/logistics/requests/bulk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v2/logistics/requests/bulk"
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"Content-Type": "<content-type>"
}
response = requests.post(url, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/v2/logistics/requests/bulk \
--header 'Content-Type: <content-type>' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>'{
"success": 123,
"failed": 123,
"results": [
{}
],
"errors": [
{}
]
}← Logistics API
Requests over the cap get HTTP
v2 of Create Logistics Requests (Bulk). It
accepts the exact same request body and returns the same response shape, but the
distance and emissions calculation for every record is performed asynchronously by a
background worker instead of inline. The endpoint returns as soon as the records are
persisted, which makes it well suited for large daily batches.
Same contract as v1. Headers, body parameters, validation, deduplication and the
5,000-record limit are identical to
POST /v1/logistics/requests/bulk. See the
v1 reference for the full request
documentation.v1 vs v2
| Behaviour | v1 (/v1/logistics/requests/bulk) | v2 (/v2/logistics/requests/bulk) |
|---|---|---|
| Distance & emissions | Calculated inline for every record before responding | Deferred to a background worker |
results[].co2e | Final emissions value | null while the async calculation is pending |
| Response latency | Scales with batch size (geocoding + distance APIs) | Low and roughly constant |
| Progress tracking | — | A processing job is created and updated as records are calculated |
| Sync-phase errors (validation, in-batch duplicates) | Returned in errors[] | Returned in errors[] and recorded on the processing job |
In v2, each
results[].co2e is null in the immediate response. Distances and
emissions are filled in asynchronously. Read the final values back via
GET /v1/logistics/requests, and track overall
progress through the processing job surfaced in the activity panel.Request
Headers
string
required
Your API key for authentication
string
required
UUID of the organization the request belongs to
string
required
Must be
application/jsonBody Parameters
The request body is identical to v1.curl -X POST "https://api.dcycle.io/v2/logistics/requests/bulk" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"origin": "Madrid, Spain",
"destination": "Barcelona, Spain",
"origin_country": "ES",
"load": 1000,
"load_unit": "kg",
"toc": "truck_diesel",
"movement_id": "SHIP-001"
}
],
"options": { "continue_on_error": true }
}'
import os
import requests
response = requests.post(
"https://api.dcycle.io/v2/logistics/requests/bulk",
headers={
"x-api-key": os.environ["DCYCLE_API_KEY"],
"x-organization-id": os.environ["DCYCLE_ORG_ID"],
},
json={
"records": [
{
"origin": "Madrid, Spain",
"destination": "Barcelona, Spain",
"origin_country": "ES",
"load": 1000,
"load_unit": "kg",
"toc": "truck_diesel",
"movement_id": "SHIP-001",
}
],
"options": {"continue_on_error": True},
},
)
result = response.json()
print(f"Accepted {result['success']}/{result['total_received']} records for async calculation")
const axios = require('axios');
axios.post('https://api.dcycle.io/v2/logistics/requests/bulk', {
records: [
{
origin: 'Madrid, Spain',
destination: 'Barcelona, Spain',
origin_country: 'ES',
load: 1000,
load_unit: 'kg',
toc: 'truck_diesel',
movement_id: 'SHIP-001',
},
],
options: { continue_on_error: true },
}, {
headers: {
'x-api-key': process.env.DCYCLE_API_KEY,
'x-organization-id': process.env.DCYCLE_ORG_ID,
},
}).then(response => {
const { success, total_received } = response.data;
console.log(`Accepted ${success}/${total_received} records for async calculation`);
});
Response
Successful Response
The response shape matches v1. The key difference is that eachresults[].co2e is null
because emissions are not yet calculated when the response is returned.
{
"total_received": 3,
"total_processed": 3,
"success": 3,
"failed": 0,
"results": [
{
"index": 0,
"id": "0d9b8817-fc47-47c3-b134-b3565ae1a57f",
"movement_id": "SHIP-001",
"package_id": null,
"co2e": null
},
{
"index": 1,
"id": "683a0184-6dac-44ab-80a2-ce31b14ce927",
"movement_id": "SHIP-002",
"package_id": null,
"co2e": null
}
],
"errors": []
}
integer
Number of records accepted and enqueued for asynchronous calculation (records that passed
synchronous validation and deduplication).
integer
Number of records that failed synchronous validation or were rejected as in-batch
duplicates. Failures detected during the asynchronous calculation phase (e.g. missing
distance or load) are reported on the processing job, not in this response.
array
One entry per accepted record. Each
co2e is null until the asynchronous calculation
completes.array
Synchronous-phase errors only (validation, in-batch duplicates), each with
index,
movement_id and error.Tracking progress
A processing job is created for the batch and updated as records are calculated. Its status movesPENDING → RUNNING → COMPLETED (or FAILED), with per-record success/failure counts
and a capped list of error entries (stage: "sync" for validation/dedup, stage: "calculation"
for async failures such as NO_TOC, NO_LOAD or NO_DISTANCE). The job is visible in the
activity panel.
Read the calculated emissions back once the job completes:
curl -X GET "https://api.dcycle.io/v1/logistics/requests?file_id[]=..." \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}"
Common Errors
401 Unauthorized
Cause: Missing or invalid API key{"detail": "Invalid API key for organization", "code": "INVALID_API_KEY"}
403 Forbidden
Cause: The authenticated user is not a member of the organization{"detail": "Logged User is not Member of Organization", "code": "LOGGED_USER_NOT_MEMBER"}
422 Unprocessable Entity
Cause: Invalid or missing required fields in the request body{
"detail": [
{
"loc": ["body", "requests"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
Migrating from v1? The request body is unchanged. Update the URL prefix to
/v2, treat
results[].co2e as pending (null), and read final emissions back from the list endpoint
or wait for the processing job to complete.Limits
| Limit | Value |
|---|---|
| Maximum concurrent requests | 10 per API key, per endpoint |
| Recommended concurrency | 8 (leaving headroom under the limit) |
429 with a Retry-After header. The cap is on requests in
flight at once, not on requests per second — see Rate Limits.
Related Endpoints
Create Request (v2)
Create a single request
List Requests
Retrieve requests with filtering and pagination
Upload CSV
Bulk import via CSV file
List Packages
View aggregated package emissions
Was this page helpful?