---
title: "Import an Excel file into Anagrafiche"
method: POST
path: "/api/v1/rest/anagrafiche/imports/{document_id}"
tags: ["Contacts"]
---

# Import an Excel file into Anagrafiche

`POST /api/v1/rest/anagrafiche/imports/{document_id}`

## Request

- Base URL: `https://api.custodo.ai`
- URL: `https://api.custodo.ai/api/v1/rest/anagrafiche/imports/{document_id}`
- Auth: HTTP bearer

Imports the Excel workbook an Archivio document holds into Anagrafiche, in ONE transaction: creates the new anagrafiche and, with existing "update", brings the ones already in the register in line with the file — their employments and logins included — exactly what anagrafiche_analyse_spreadsheet reported for the same arguments, so analyse first and pass the SAME arguments. Refused, with the report, while a row has a problem, unless skip_invalid_rows is true. The person approves it on a card showing the counts, the columns and the roles before anything is written; it cannot be undone row by row.

## Path parameters

- `document_id` string, uuid, required

## Headers

- `X-Tenant-Id` string, uuid

## Request body

- object
  - `columns` object: The file’s own column headers, EXACTLY as the analysis lists them, mapped to the register’s fields — e.g. {"Cliente": "name", "Cod. Fiscale": "tax_code", "Nazionalità": "ignore"}. Only needed for headers the analysis did not recognise (`read_as` null) or read wrongly; "ignore" leaves a column unread. Every row needs `name` (the denominazione) — or, for a person, `first_name`/`last_name`. `company` is the company a PERSON belongs to, by its name. For an employee: `employee_code` (matricola), `manager` (their Responsabile’s name — another employee, in the register or in the file), `hired_on`, `left_on`. The organisation’s own fields are "custom.<key>", as the analysis lists them under `custom_fields`.
  - `roles` string[]: Roles EVERY row takes, on top of any «Ruoli» column: a list of customers → ["cliente"], of suppliers → ["fornitore"]. Keys from anagrafiche_list_roles.
  - `existing` 'update' | 'skip': A row whose anagrafica is ALREADY in the register — same codice fiscale, else same partita IVA, else same name — "update"s it (default: only cells that carry a value change anything; roles and labels are added, never removed; notes are never overwritten; the kind never changes) or is left alone with "skip". Either way nothing is duplicated.
  - `skip_invalid_rows` boolean: false (default): one row with a problem blocks the whole import. true: the rows that pass are written and the others are left out and listed. Set it only after the person has seen which rows would be left out and agreed.
  - `sheet` string: The tab to read, by name, when the workbook has several (the analysis lists them). A workbook of one tab needs nothing.

## Response `200`

Done. `data` is the tool’s own answer.

- RestResult
  - `ok` true, required
  - `data` unknown, required

## Other responses

- `400`: The arguments did not validate: `error.message` names the field, what it expects and what arrived.
- `401`: No API key, or one that is malformed, unknown, revoked or expired.
- `403`: The call never ran: the module is off for this organisation, the credential lacks the permission or the module, the tier does not cover it, or the tool is destructive and the key was not minted for that.
- `404`: Nothing with that id in this organisation.
- `409`: The record is in a state that does not allow it — under legal hold, already sent, already closed. `error.code` says which.
- `422`: The tool ran and refused, in a sentence of its own (`TOOL_REFUSED`): the message says what to change. Retrying the same call will not help.
- `429`: The API key has spent its minute, or its day. Every request a key makes counts. See `Retry-After`.

---

[API](https://skmtc.dev/custodo/apis/custodo-integrazioni.md) · [All operations](https://skmtc.dev/custodo/apis/custodo-integrazioni/llms.txt) · [OpenAPI document](https://skmtc.dev/custodo/apis/custodo-integrazioni/revisions/16d336d3ec2a?raw)
