Import results, task import retries and new read fields
Contact imports report updated rows, warnings and why each row was skipped; task imports retry safely; invoices expose origin; quotes and proformas expose operation_regime.
5 October 2026
This release changes the contract of the import operations and adds read fields to invoices, quotes and proformas. No operation is new: every one listed below already existed and its response or behavior was updated. The list of operations is at the end of the page.
Contact import tracking
GET /v1/contacts/imports/{id},
POST /v1/contacts/import and
POST /v1/contacts/import/preview
(and the MCP tools get_contact_import, import_contacts and preview_contacts_import)
report more about what an import did.
| Field | Meaning |
|---|---|
updated_count | Rows that updated an existing contact. added_count no longer includes them: total_rows = added_count + updated_count + skipped_count + failed_count + unprocessed_count. |
warnings_count | Warnings produced by the import. It is not part of that sum. |
outcome_kind | changes_applied, nothing_changed, partial or failed. completed does not mean something changed: nothing_changed is an import that finished without creating or updating anything, so do not present it as a success. partial has applied and failed rows; failed has failed rows and none applied. |
skip_reasons | Skipped rows counted by reason. |
first_diagnostics | Up to 20 grouped diagnostics (code, field, severity, message, count, first_row). |
outcomes_truncated | true when outcomes holds the first 500 rows and the import has more. |
reason (per row) | Why a row was skipped, failed or left the contact unchanged (already_exists, no_changes, merge_review_required, update_not_allowed, identity_conflict, validation_failed…); null when the row was applied. |
The preview and the synchronous import response add the same updated_count,
warnings_count, skip_reasons and per-row reason, plus the skip action and
counter: rows that change nothing because they are identical to the existing contact
(no_changes) or target an archived contact (update_not_allowed). The preview
also reports merge_candidate rows (see merge below).
The synchronous response of POST /v1/contacts/import (and the import_contacts tool) also carries outcome_kind, with the same values as the tracking resource. It is null in the preview, in dry_run and in queued imports (202), and takes its value when the execution finishes.
What conflict_strategy does
conflict_strategy decides what happens when a row matches an existing contact by
tax_id or external_id:
| Value | Behavior |
|---|---|
reject (default) | Any match is a conflict, except when the row only adds a role the contact does not have yet. |
update | Applies the fields that carry a value. An empty cell never clears a field. |
merge | Applies nothing and flags the row for manual review: result=skipped, reason=merge_review_required. |
An import never changes the tax_id or the external_id of an existing contact and
never reactivates an archived one.
Mapping and columns
A mapping that points to a column the file does not have is now rejected with
422 mapping_header_not_found with param: mapping. Read the headers again and
send a mapping whose keys match them exactly. The code is in the
error catalog.
The importer accepts four new columns: iban and bic (a bank account added to the
contact's existing ones: collection for a customer, payment for a supplier), customer_default_price_list_name
(name of an existing price list, instead of its UUID) and supplier_default_tax_code
(code of an existing tax, instead of its UUID).
A negative retention percentage (customer_retention_rate, supplier_retention_rate; the legacy customer convention, for example -15) is stored as a positive value (15), and the row gets the RETENTION_SIGN_NORMALIZED warning in its diagnostics.
Import template
GET /v1/contacts/import/template
now takes format=csv|xlsx. csv is the default and returns a UTF-8 file with a BOM
and only the headers, separated by semicolons. xlsx returns a workbook with the Data,
Instructions, Examples and Allowed values sheets. The response is an attachment
(plantilla-contactos.csv or plantilla-contactos.xlsx, with Content-Disposition). It
still requires contacts:read and contains no company data.
Task import retries
POST /v1/projects/{project}/tasks/import
and the MCP tool import_project_tasks can now be retried without duplicating tasks:
- Repeating the call with the same key and the same document returns the report of the first call and creates nothing.
- Reusing the key with a different document answers
409idempotency_key_reused. - A new key, or no key in MCP, creates a new copy of the tasks. In MCP the
idempotency_keyargument is optional; over HTTP theIdempotency-Keyheader stays required.
The report adds warnings_total, the number of warnings the import produced, and
warnings_truncated, true when some were left out. Only the first 200 warnings are
kept in warnings.
New read fields
| Resource | Field | Meaning |
|---|---|---|
| Invoice (v1 and MCP) | origin | native for an invoice issued in Factuarea, historical_import for a historical invoice registered by import: literal number from the file, no series counter and no VeriFactu record. |
| Quote | reference | Origin number of the document, for example the one it had in a previous system when imported. null if not set. |
| Quote and proforma | operation_regime | VAT operation regime: general, intracomunitaria, importacion_exportacion or isp. |
The reason of a stock movement also admits initial.