> ## 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 Vehicles (v2)

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

[← Vehicles API](/api-reference/vehicles/overview)

Create one or many vehicles of your fleet. A vehicle is master data: creating it calculates nothing (its emissions
come from its [consumptions](/api-reference/vehicles/consumptions)), so the request is **synchronous**: it answers
`201 Created` with every vehicle, in the order you sent them, ready to take consumptions.

<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/vehicles" \
    -H "x-api-key: ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_ID}" \
    -H "Idempotency-Key: 6f5e4d3c-2b1a-4f0e-9d8c-7b6a5f4e3d2c" \
    -H "Content-Type: application/json" \
    -d '{
      "records": [
        {
          "license_plate": "1234 ABC",
          "name": "Delivery van 01",
          "type": "freight",
          "ownership": "owned",
          "country": "ES",
          "unknown_vehicle_id": "0ec95def-e866-4d04-89a0-87d8b4ba4527",
          "vehicle_fuel_ids": ["407ff7e3-aa7f-4844-94b1-e621b6fbdd5e"],
          "registration_year": 2021,
          "client_row_id": "FLEET-001"
        }
      ]
    }'
  ```

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

  import requests

  response = requests.post(
      "https://api.dcycle.io/v2/vehicles",
      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": [
              {
                  "license_plate": "1234 ABC",
                  "type": "passenger",
                  "ownership": "rented",
                  "country": "ES",
                  "unknown_vehicle_id": "0ec95def-e866-4d04-89a0-87d8b4ba4527",
                  "vehicle_fuel_ids": ["407ff7e3-aa7f-4844-94b1-e621b6fbdd5e"],
              }
          ]
      },
      timeout=60,
  )
  response.raise_for_status()
  for item in response.json()["items"]:
      print(item["client_row_id"], item["vehicle"]["id"])
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "items": [
      {
        "source_row_index": 0,
        "client_row_id": "FLEET-001",
        "vehicle": {
          "id": "8a7b6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
          "organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
          "license_plate": "1234 ABC",
          "name": "Delivery van 01",
          "type": "freight",
          "ownership": "owned",
          "country": "ES",
          "unknown_vehicle_id": "0ec95def-e866-4d04-89a0-87d8b4ba4527",
          "vehicle_fuel_ids": ["407ff7e3-aa7f-4844-94b1-e621b6fbdd5e"],
          "registration_year": 2021,
          "market_segment": null,
          "size": null,
          "status": "active",
          "created_at": "2026-10-19T09:12:44.031Z",
          "updated_at": "2026-10-19T09:12:44.031Z"
        }
      }
    ]
  }
  ```

  ```json 422 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "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": "FLEET-001",
        "error_code": "LICENSE_PLATE_ALREADY_EXISTS",
        "error_params": { "field": "license_plate", "value": "1234 ABC" }
      }
    ],
    "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": 1, "valid": 1 }
  ```
</ResponseExample>

## How it works

1. **Every record is checked**, with the rules of the Data Importer: the vehicle class and its fuels exist and the
   fuels are ones that class can run on, the country is known and the plate is free. If any record is invalid the
   **whole** request is rejected with `422` and nothing is created; the answer lists every invalid record.
2. **Every vehicle 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. **The vehicles belong to the `x-organization-id` organization.** A record cannot name another one: send each
   organization's vehicles with its own `x-organization-id`.

## Request

### Headers

<ParamField header="x-api-key" type="string" required>
  Your API key (see [Authentication](/api-reference/introduction#authentication)).
</ParamField>

<ParamField header="x-organization-id" type="string" required>
  The organization the vehicles belong to.
</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 vehicles (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`.
</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 vehicles to create, 1 to 1,000. A field not listed here is rejected (`SCHEMA_INVALID`).

  <Expandable title="record">
    <ParamField body="license_plate" type="string" required>
      3 to 255 characters, stored as sent (trimmed). It must be free among the organization's active vehicles and
      appear once in the request; plates are compared without spaces, dashes, accents or case, so `1234 ABC` and
      `1234-abc` are the same plate.
    </ParamField>

    <ParamField body="type" type="string" required>
      `passenger` or `freight`.
    </ParamField>

    <ParamField body="ownership" type="string" required>
      `owned` (scope 1) or `rented` (scope 3).
    </ParamField>

    <ParamField body="country" type="string" required>
      Where the vehicle is used, ISO 3166-1 alpha-2 (`ES`, `FR`...; case-insensitive, returned uppercase). It picks the
      emission factors of its consumptions.
    </ParamField>

    <ParamField body="unknown_vehicle_id" type="uuid" required>
      The vehicle class (passenger car, van, truck...): an `id` of
      [List Unknown Vehicles](/api-reference/unknown-vehicles/list), other than `no_vehicle`.
    </ParamField>

    <ParamField body="vehicle_fuel_ids" type="array[uuid]" required>
      The fuels the vehicle runs on, each once; the first is its primary fuel. Each an `id` of
      [List Vehicle Fuels](/api-reference/vehicle-fuels/list) that the vehicle class can run on.
    </ParamField>

    <ParamField body="name" type="string">
      Your name for the vehicle, up to 255 characters.
    </ParamField>

    <ParamField body="registration_year" type="integer">
      Year of registration, from 1900 to the current year.
    </ParamField>

    <ParamField body="market_segment" type="string">
      Car market segment: `mini`, `supermini`, `lower_medium`, `upper_medium`, `executive`, `luxury`, `sports`,
      `dual_purpose_4x4` or `mpv` (see [List Market Segments](/api-reference/vehicles/market-segments)).
    </ParamField>

    <ParamField body="size" type="string">
      Car size: `small_car`, `medium`, `large_car` or `average_car`.
    </ParamField>

    <ParamField body="custom_ef_record_id" type="uuid">
      A record of your [custom emission factor databases](/api-reference/custom-emission-factors/overview) to
      calculate its consumptions with, instead of the default: find it with
      [List Records](/api-reference/custom-emission-factors/list-records). Its `activity_categories` must include
      `transport`, and the vehicle must have exactly one fuel.
    </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 `vehicle`: `id`, `organization_id`, `license_plate`, `name`, `type`, `ownership`, `country`,
`unknown_vehicle_id`, `vehicle_fuel_ids` (primary first), `registration_year`, `market_segment`, `size`, `status`
(`active`) and UTC timestamps ending in `Z`. Its emissions come with its consumptions: there is no `co2e` here.

## 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: a missing or unknown field (e.g. `organization_id`), a plate under 3 characters, a fuel listed twice, a `registration_year` in the future, `custom_ef_record_id` with more than one fuel... `error_params.errors` says where. |
| `LICENSE_PLATE_ALREADY_EXISTS` | An active vehicle of the organization already has this plate (compared without spaces, dashes, accents or case). |
| `DUPLICATE_LICENSE_PLATE` | Another record of the request has the same plate. |
| `REFERENCE_NOT_FOUND` | `country`, `unknown_vehicle_id` or a fuel of `vehicle_fuel_ids` does not exist (`error_params.field` says which). |
| `FUEL_NOT_ALLOWED_FOR_VEHICLE_TYPE` | A fuel of `vehicle_fuel_ids` is not one the vehicle class runs on (`error_params.value` is the fuel). |
| `MULTIDB_CUSTOM_RECORD_NOT_FOUND_OR_DISABLED` | `custom_ef_record_id` does not exist, is disabled or is not visible from your organization. |
| `MULTIDB_CUSTOM_RECORD_INCOMPATIBLE_CATEGORY` | `custom_ef_record_id` is not configured for the `transport` activity category. |

`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](/api-reference/rate-limits).

## 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 vehicles 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 Vehicles (v2)" icon="trash" href="/api-reference/vehicles/delete-v2">
    Delete up to 1,000 vehicles with their consumptions
  </Card>

  <Card title="List Unknown Vehicles" icon="car" href="/api-reference/unknown-vehicles/list">
    Ids for `unknown_vehicle_id`
  </Card>

  <Card title="List Vehicle Fuels" icon="gas-pump" href="/api-reference/vehicle-fuels/list">
    Ids for `vehicle_fuel_ids`
  </Card>

  <Card title="Vehicle Consumptions" icon="route" href="/api-reference/vehicles/consumptions">
    What the vehicles' emissions come from
  </Card>
</CardGroup>


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