# Upload a spreadsheet of units

> `POST /imports` · Scope: `import` · operationId `createImport`

Editor and above, or an API key with the `import` scope (ADR-026). A CSV (UTF-8, UTF-16 or
Windows-1252; `;`, `,`, tab or `|` separated) or XLSX file of at most 10 MB, 10 000 rows and 200
columns; the first non-empty row holds the headers. The answer is the import with a mapping
proposed from the headers (registry CSV headers, aliases, labels; units such as `(kWh)` are
converted), or taken from the import preset named in `preset` (the ERP registry): a preset maps
the columns it knows by their headers and leaves the others unmapped.

A key stages the import only: members of the organisation commit it and approve its values in
the portal, so declared data still enters through a member's decision.

## Request body (`multipart/form-data`)

- **file** `any` (required)
- **preset** `string`: An import preset of the ERP registry (`getErpRegistry`, ADR-026): which column header of an ERP export maps to which registry field.
- **sheet** `string`: The XLSX worksheet to read (the first one when omitted).

## Responses

### 201 (`application/json`)

The import.

- **approved_at** `string (date-time)`
- **approved_by** `string (uuid)`
- **committed_at** `string (date-time)`
- **created_at** `string (date-time)` (required)
- **created_by** `UserRef`
  - **display_name** `string` (required)
  - **id** `string (uuid)` (required)
- **created_by_api_key** `ApiKeyRef`: An organisation API key (ADR-017) that reported an event (source `api`) or staged an import (ADR-026).
  - **id** `string (uuid)` (required)
  - **name** `string` (required)
- **filename** `string` (required)
- **format** `string` (required, one of: `csv`, `xlsx`)
- **headers** `string[]` (required)
- **id** `string (uuid)` (required)
- **mapping** `ColumnMapping[]` (required)
  - **auto** `boolean`: Proposed by the server from the header.
  - **column** `integer` (required): The 0-based column of the file.
  - **header** `string`: The column's header (set by the server).
  - **target** `string`: A target of `listImportTargets`: a field key, `key[n].property` (list item n, 1-based), `key.property` (object property) or `model_version`. Empty or missing: the column is ignored.
  - **unit** `string`: The unit the column's numbers are written in when it differs from the field's (e.g. `kWh` for a field in Wh).
- **options** `ImportOptions` (required)
  - **battery_model_id** `string (uuid)`: The model of rows without a model column.
  - **facility_id** `string (uuid)`: The place of manufacture of rows without one.
- **preset** `string`: An import preset of the ERP registry (`getErpRegistry`, ADR-026): which column header of an ERP export maps to which registry field.
- **row_count** `integer` (required): Data rows (empty rows are left out).
- **row_version** `integer (int64)` (required): Optimistic-concurrency version; send it back as `If-Match` when updating.
- **sample_rows** `string[][]` (required): The first data rows of the file as read (at most 5), to show example values while mapping.
- **sheet** `string`: The XLSX worksheet that was read.
- **size_bytes** `integer (int64)` (required)
- **status** `string` (required, one of: `uploaded`, `validating`, `validated`, `committing`, `committed`, `failed`): `uploaded` (mapping can change) → `validating` → `validated` → `committing` → `committed`; `failed` when the file could not be validated (validate again). A changed mapping sends a validated import back to `uploaded`.
- **summary** `ImportSummary`
  - **approved** `integer` (required): Imported values approved by import approvals.
  - **created** `integer` (required): Units the commit created.
  - **duplicates** `integer` (required): Rows whose serial number repeats an earlier row or an existing unit; not imported.
  - **errors** `integer` (required): Rows with errors; not imported.
  - **not_approved** `integer` (required): Imported values the last approval left for individual review.
  - **rows** `integer` (required)
  - **valid** `integer` (required): Rows without messages.
  - **warnings** `integer` (required): Rows with warnings only; they are imported.
- **updated_at** `string (date-time)` (required)
- **validated_at** `string (date-time)`

### 400 (`application/problem+json`)

The request is malformed or failed validation (`validation_error`), or a token is invalid or expired (`invalid_token`).

### 401 (`application/problem+json`)

The API key is missing, unknown or revoked (`unauthenticated`).

### 403 (`application/problem+json`)

The API key may not perform this action (`forbidden`): it lacks the operation's scope, or the action needs more than a viewer's rights.

### 413 (`application/problem+json`)

The request body exceeds the size limit (`payload_too_large`).

### default (`application/problem+json`)

Any other problem, e.g. `internal_error`.

## Example

```bash title="cURL"
curl -X POST "https://passport.kabin.sh/api/v1/imports" \
  -H "Authorization: Bearer $BATTERYPASS_API_KEY"
```
