Bulk Upload Vehicles
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'x-user-id': '<x-user-id>',
'Content-Type': 'application/json'
},
body: JSON.stringify({file_name: '<string>'})
};
fetch('https://api.dcycle.io/api/v1/vehicles/bulk/csv', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/api/v1/vehicles/bulk/csv"
payload = { "file_name": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"x-user-id": "<x-user-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/api/v1/vehicles/bulk/csv \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>' \
--header 'x-user-id: <x-user-id>' \
--data '
{
"file_name": "<string>"
}
'{
"upload_url": "<string>",
"file_name": "<string>",
"file_id": "<string>",
"destination_file_key": "<string>",
"message": "<string>"
}Bulk Upload Vehicles
Get a presigned URL to upload multiple vehicles via CSV
POST
/
api
/
v1
/
vehicles
/
bulk
/
csv
Bulk Upload Vehicles
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'x-user-id': '<x-user-id>',
'Content-Type': 'application/json'
},
body: JSON.stringify({file_name: '<string>'})
};
fetch('https://api.dcycle.io/api/v1/vehicles/bulk/csv', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/api/v1/vehicles/bulk/csv"
payload = { "file_name": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"x-user-id": "<x-user-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/api/v1/vehicles/bulk/csv \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>' \
--header 'x-user-id: <x-user-id>' \
--data '
{
"file_name": "<string>"
}
'{
"upload_url": "<string>",
"file_name": "<string>",
"file_id": "<string>",
"destination_file_key": "<string>",
"message": "<string>"
}Bulk Upload Vehicles
Upload hundreds of vehicles at once via a CSV file. This endpoint returns a presigned S3 URL so you can upload your file, which will be processed asynchronously.This method is recommended for bulk uploads. Vehicles are persisted in the database and emissions are calculated automatically based on consumption data.
Upload Flow
1
Request presigned URL
Make a POST request to
/api/v1/vehicles/bulk/csv with your file name2
Upload to S3
Use the presigned URL to upload your CSV directly to S3 (PUT request)
3
Asynchronous processing
The system processes your file in the background, creating vehicles and validating data
4
Verify results
Check your fleet with the List Vehicles endpoint
Step 1: Request Presigned URL
Request
Headers
string
required
Your API key for authenticationExample:
sk_live_1234567890abcdefstring
required
Your organization UUIDExample:
ff4adcc7-8172-45fe-9cf1-e90a6de53aa9string
required
Your user UUIDExample:
a1b2c3d4-e5f6-7890-abcd-ef1234567890Body Parameters
string
required
Name of the CSV file you’re going to uploadExample:
"company_fleet_2024.csv"Response
string
Presigned S3 URL to upload the vehicles file
string
Sanitized file name (alphanumeric only)
string
File UUID for tracking
string
Full S3 key where file will be stored
string
Confirmation message
Example
curl -X POST "https://api.dcycle.io/api/v1/vehicles/bulk/csv" \
-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 '{
"file_name": "company_fleet_2024.csv"
}'
import requests
import os
api_key = os.getenv("DCYCLE_API_KEY")
org_id = os.getenv("DCYCLE_ORG_ID")
user_id = os.getenv("DCYCLE_USER_ID")
headers = {
"Authorization": f"Bearer {api_key}",
"x-organization-id": org_id,
"x-user-id": user_id,
"Content-Type": "application/json"
}
payload = {
"file_name": "company_fleet_2024.csv"
}
response = requests.post(
"https://api.dcycle.io/api/v1/vehicles/bulk/csv",
headers=headers,
json=payload
)
result = response.json()
upload_url = result["upload_url"]
file_id = result["file_id"]
print(f"Upload URL obtained: {upload_url[:50]}...")
print(f"File ID: {file_id}")
const axios = require('axios');
const apiKey = process.env.DCYCLE_API_KEY;
const orgId = process.env.DCYCLE_ORG_ID;
const userId = process.env.DCYCLE_USER_ID;
const headers = {
'Authorization': `Bearer ${apiKey}`,
'x-organization-id': orgId,
'x-user-id': userId,
'Content-Type': 'application/json'
};
const payload = {
file_name: 'company_fleet_2024.csv'
};
axios.post(
'https://api.dcycle.io/api/v1/vehicles/bulk/csv',
payload,
{ headers }
)
.then(response => {
const { upload_url, file_id } = response.data;
console.log('Upload URL:', upload_url.substring(0, 50) + '...');
console.log('File ID:', file_id);
})
.catch(error => console.error(error));
Successful Response
{
"upload_url": "https://dcycle-vehicles.s3.amazonaws.com/files/dcycle/...",
"file_name": "company_fleet_2024",
"file_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"destination_file_key": "files/dcycle/.../company_fleet_2024.csv",
"message": "Upload pre-signed url generated"
}
Step 2: Upload CSV to S3
Use the presigned URL to upload your CSV file directly to S3:# The presigned URL already includes authentication parameters
curl -X PUT "${UPLOAD_URL}" \
-H "Content-Type: text/csv" \
--data-binary @company_fleet_2024.csv
import requests
# Read CSV file
with open('company_fleet_2024.csv', 'rb') as file:
csv_data = file.read()
# Upload to S3
response = requests.put(
upload_url,
data=csv_data,
headers={'Content-Type': 'text/csv'}
)
if response.status_code == 200:
print("✅ File uploaded successfully")
else:
print(f"❌ Error: {response.status_code}")
const fs = require('fs');
const axios = require('axios');
// Read CSV file
const csvData = fs.readFileSync('company_fleet_2024.csv');
// Upload to S3
axios.put(uploadUrl, csvData, {
headers: { 'Content-Type': 'text/csv' }
})
.then(() => console.log('✅ File uploaded successfully'))
.catch(error => console.error('❌ Error:', error));
The presigned URL expires in 15 minutes. Make sure to upload the file within that time.
CSV Format
The CSV must follow this structure for creating vehicles:name,license_plate,type,ownership,country,is_known,known_vehicle_id,vehicle_fuel_id,registration_year,market_segment,size
Company Van #1,1234-ABC,freight,owned,ES,true,b2c3d4e5-f6g7-8901-bcde-fg2345678901,c3d4e5f6-g7h8-9012-cdef-gh3456789012,2020,lower_medium,medium
CEO Car,9876-XYZ,passenger,owned,ES,true,e5f6g7h8-i9j0-1234-efgh-ij5678901234,f6g7h8i9-j0k1-2345-fghi-jk6789012345,2023,executive,large_car
Delivery Truck,5555-DEF,freight,rented,ES,false,,i9j0k1l2-m3n4-5678-ijkl-mn9012345678,2019,,
Required Columns
| Column | Description | Valid Values | Example |
|---|---|---|---|
type | Vehicle usage type | passenger, freight | "freight" |
ownership | Ownership status | owned, rented | "owned" |
country | ISO 3166-1 alpha-2 country code | ES, FR, DE, etc. | "ES" |
is_known | Whether from known database | true, false | true |
Optional Columns
| Column | Description | Example |
|---|---|---|
name | Vehicle name or description | "Company Van #1" |
license_plate | License plate number | "1234-ABC" |
known_vehicle_id | UUID from known vehicles database (if is_known: true) | UUID string |
vehicle_fuel_id | UUID of fuel type | UUID string |
registration_year | Year first registered | 2020 |
market_segment | Market segment (for passenger vehicles) | mini, supermini, executive, etc. |
size | Vehicle size classification | small_car, medium, large_car, average_car |
Column Details
is_known:true: Vehicle from Dcycle’s known vehicles database. Must provideknown_vehicle_id.false: Custom vehicle. System will create an unknown vehicle entry.
passenger: Company cars, executive vehicles, personal usefreight: Delivery vans, trucks, commercial vehicles
owned: Vehicles owned by your organizationrented: Leased or rented vehicles
mini- City carssupermini- Small carslower_medium- Compact carsupper_medium- Mid-size carsexecutive- Large carsluxury- Premium carssports- Sports carsdual_purpose_4x4- SUVsmpv- Minivans
Download Template
Download CSV Template
Template with correct format and sample data
Step 3: Asynchronous Processing
Once the CSV is uploaded:- Validation: The system validates format, vehicle IDs, and data
- Processing: Each row is processed and vehicles are created
- Emission Calculation: CO2e values initialized to 0 (updated when consumption data is added)
- Notification: (Coming soon) You’ll receive a webhook when complete
Processing can take from a few seconds to several minutes depending on file size.
Step 4: Verify Results
After processing, you can query your vehicles:# List vehicles
curl "https://api.dcycle.io/api/v1/vehicles" \
-H "Authorization: Bearer ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "x-user-id: ${DCYCLE_USER_ID}"
Complete Example Script
import requests
import os
from time import sleep
class DcycleVehicles:
def __init__(self, api_key, org_id, user_id):
self.api_key = api_key
self.org_id = org_id
self.user_id = user_id
self.base_url = "https://api.dcycle.io"
self.headers = {
"Authorization": f"Bearer {api_key}",
"x-organization-id": org_id,
"x-user-id": user_id,
"Content-Type": "application/json"
}
def upload_csv(self, csv_file_path):
"""Complete CSV upload: presigned URL + upload + verification"""
# 1. Get presigned URL
file_name = os.path.basename(csv_file_path)
response = requests.post(
f"{self.base_url}/api/v1/vehicles/bulk/csv",
headers=self.headers,
json={"file_name": file_name}
)
response.raise_for_status()
upload_url = response.json()["upload_url"]
file_id = response.json()["file_id"]
print(f"✅ Presigned URL obtained (File ID: {file_id})")
# 2. Upload file
with open(csv_file_path, 'rb') as f:
upload_response = requests.put(
upload_url,
data=f,
headers={'Content-Type': 'text/csv'}
)
upload_response.raise_for_status()
print(f"✅ File uploaded successfully")
# 3. Wait for processing (optional)
print("⏳ Processing... (this may take a few minutes)")
sleep(30) # Wait 30 seconds
# 4. Verify vehicles
vehicles = self.get_vehicles()
print(f"✅ Total vehicles in fleet: {vehicles['total']}")
return file_id
def get_vehicles(self):
"""List vehicles"""
response = requests.get(
f"{self.base_url}/api/v1/vehicles",
headers=self.headers
)
response.raise_for_status()
return response.json()
# Usage
if __name__ == "__main__":
client = DcycleVehicles(
api_key=os.getenv("DCYCLE_API_KEY"),
org_id=os.getenv("DCYCLE_ORG_ID"),
user_id=os.getenv("DCYCLE_USER_ID")
)
client.upload_csv("company_fleet_2024.csv")
#!/bin/bash
# Variables
API_KEY="${DCYCLE_API_KEY}"
ORG_ID="${DCYCLE_ORG_ID}"
USER_ID="${DCYCLE_USER_ID}"
CSV_FILE="company_fleet_2024.csv"
BASE_URL="https://api.dcycle.io"
# 1. Get presigned URL
echo "📤 Requesting presigned URL..."
RESPONSE=$(curl -s -X POST "${BASE_URL}/api/v1/vehicles/bulk/csv" \
-H "Authorization: Bearer ${API_KEY}" \
-H "x-organization-id: ${ORG_ID}" \
-H "x-user-id: ${USER_ID}" \
-H "Content-Type: application/json" \
-d "{\"file_name\": \"${CSV_FILE}\"}")
UPLOAD_URL=$(echo $RESPONSE | jq -r '.upload_url')
FILE_ID=$(echo $RESPONSE | jq -r '.file_id')
echo "✅ URL obtained (File ID: ${FILE_ID})"
# 2. Upload file
echo "📤 Uploading CSV file..."
curl -X PUT "${UPLOAD_URL}" \
-H "Content-Type: text/csv" \
--data-binary @"${CSV_FILE}"
echo "✅ File uploaded successfully"
echo "⏳ File is being processed..."
Common Errors
400 Bad Request - Missing file_name
Cause: Field required{
"detail": "Field required",
"field": "file_name"
}
file_name parameter in the request body.
403 Forbidden - URL Expired
Cause: The presigned URL expired (15 minutes) Solution: Request a new presigned URL and upload the file immediately.422 Validation Error - CSV Format
Cause: The CSV has incorrect format or missing required columns Solution: Verify that your CSV has all required columns (type, ownership, country, is_known) and correct format.
422 Validation Error - Invalid Vehicle ID
Cause:known_vehicle_id doesn’t exist in the known vehicles database
Solution: Use the Known Vehicles endpoint to get valid vehicle IDs, or set is_known: false to create a custom vehicle.
Limits and Recommendations
| Limit | Value |
|---|---|
| Maximum file size | 100 MB |
| Maximum rows per CSV | 10,000 |
| URL expiration time | 15 minutes |
| Processing time | ~1 second per 50 vehicles |
For very large fleets (>10k vehicles), consider splitting them into multiple smaller CSVs.
Best Practices
Data Preparation
- Clean license plates: Remove special characters, use consistent format
- Validate vehicle IDs: Check that
known_vehicle_idexists before upload - Consistent naming: Use standardized vehicle names (e.g., “Van #1”, “Van #2”)
- Complete data: Include as many optional fields as possible for better reporting
Error Handling
After upload, check for vehicles withstatus: "error":
def check_for_errors():
"""Check if any vehicles failed to process"""
response = requests.get(
"https://api.dcycle.io/api/v1/vehicles",
headers=headers,
params={"filter_by": "status:error"}
)
vehicles = response.json()
if vehicles['total'] > 0:
print(f"⚠️ {vehicles['total']} vehicles have errors:")
for vehicle in vehicles['items']:
print(f" - {vehicle.get('name', 'Unnamed')}: {vehicle.get('error_messages')}")
return vehicles['total']
# Check after processing
errors_count = check_for_errors()
if errors_count == 0:
print("✅ All vehicles processed successfully")
Incremental Updates
To update existing vehicles or add new ones:- Export current fleet to CSV
- Modify or add rows
- Re-upload (existing vehicles will be updated by license plate)
Special Notes
Known vs Unknown Vehicles
Known Vehicles (is_known: true):- Must provide valid
known_vehicle_id - Emission factors are based on manufacturer data
- Includes detailed specifications (engine size, power, etc.)
- System creates generic vehicle entry
- Emission factors based on vehicle type and fuel
- Less accurate but flexible for custom vehicles
Vehicle Status After Upload
Vehicles created via CSV will have:- status:
"active"if successful,"error"if validation failed - co2e:
0.0initially (updated when consumption data is added) - created_at: Upload timestamp
Adding Consumption Data
After creating vehicles, add fuel consumption data using the Create Invoice endpoint withtype: "recharge" for electric vehicles or facility fuels for combustion vehicles.
Country Codes
Use ISO 3166-1 alpha-2 country codes:- Spain:
ES - France:
FR - Germany:
DE - United Kingdom:
GB - United States:
US
Related Endpoints
List Vehicles
View uploaded vehicles
Create Invoice
Add fuel consumption data
List Facilities
View your facilities
Authentication
Learn about API authentication
Was this page helpful?