# Import rows into a board

Put a spreadsheet's worth of rows onto a custom board in ONE call, and the way to make a board FROM data: omit boardId and send `name`, and the board is created. `columns` are ENSURED by label (case-insensitive) — a label that already exists is reused, and a kind that disagrees with the existing column is a 400 naming it. Values are coerced per kind server-side: "$1,200.50" into a currency cell, "1/15/2026" into a date, "yes/x/1" into a checkbox, "a, b" into tags, a status label into the option's value. `identity` names the columns that say which row is which, so a matching row is UPDATED rather than duplicated. Three policies, each defaulting to the first word: unknownChoice add|blank|reject (a status value the column has no option for becomes a new option, an empty cell, or a failed row); duplicates first|last|all (the file names one identity twice); dryRun true|false (plan only, nothing written, answers 200). At most 5000 rows per call — more is 413 `too_many_rows`, so page it. Answers the board, the columns and options it created, per-row outcomes (created/updated/skipped/failed with the reason), and a runId the rollback works from.

Access class: `workspace`.

## Endpoint

`POST /v1/boards/import`

## Request body

Content type: `application/json`.

```json
{
  "body": {
    "boardId": "",
    "columns": [
      {
        "kind": "string",
        "label": "string",
        "options": [
          "string"
        ]
      }
    ],
    "dryRun": true,
    "duplicates": "string",
    "identity": [
      "string"
    ],
    "name": "string",
    "purpose": "string",
    "rows": [
      {
        "Business": "string",
        "Stage": "string"
      }
    ],
    "source": "string",
    "unknownChoice": "string"
  },
  "params": {},
  "query": {}
}
```

## Responses

### 201

the action's answer

Content type: `application/json`.

```json
{
  "data": {
    "board": {
      "access": "string",
      "columns": [
        {
          "calculation": "string",
          "config": {},
          "id": "",
          "kind": "string",
          "label": "string",
          "options": [
            {
              "groupLabel": "string",
              "id": "",
              "label": "string",
              "position": 1.5,
              "tone": "string",
              "value": "string"
            }
          ],
          "position": 1.5,
          "starred": true
        }
      ],
      "createdAt": "string",
      "definitionKey": "string",
      "id": "",
      "name": "string",
      "purpose": "string",
      "rows": [
        {
          "cells": {
            "<uuid-1>": "string",
            "<uuid-2>": "string"
          },
          "createdBy": "string",
          "id": "",
          "position": 1.5
        }
      ],
      "updatedAt": "string",
      "view": "string"
    },
    "columnsCreated": [
      {
        "id": "",
        "kind": "string",
        "label": "string"
      }
    ],
    "counts": {
      "created": 1.5,
      "failed": 1.5,
      "skipped": 1.5,
      "updated": 1.5
    },
    "optionsAdded": [
      {
        "columnId": "",
        "label": "string",
        "values": [
          "string"
        ]
      }
    ],
    "results": [
      {
        "id": "",
        "outcome": "string",
        "row": 1.5
      }
    ],
    "runId": ""
  }
}
```

### default

a refusal: `{"error": "<what a person needs to read>"}`. 401 no credential, 402 the plan does not include this, 403 the seat does not, 404 the thing does not exist or is not yours to see.

Content type: `application/json`.

```json
{
  "error": "string"
}
```
