Importaciones de contactos
Previsualiza archivos de contactos, consulta resultados confirmados por fila y descarga informes de errores autorizados.
Previsualiza antes de escribir
Envía el archivo a POST /v1/contacts/import/preview e impórtalo después con POST /v1/contacts/import usando un nuevo Idempotency-Key. Ambos requieren contacts:write. HTTP admite CSV, TXT, XLSX y XLS hasta 10 MB; MCP preview_contacts_import e import_contacts admiten CSV base64 hasta 10 MB. Esta actualización no añade ODS a estos contratos públicos de subida.
La previsualización conserva las clasificaciones planificadas create, update, add_role, merge_candidate, conflict e invalid. Resuelve primero los conflictos de identidad fiscal. Una actualización conserva los campos omitidos en el archivo: omitir bank_accounts conserva las cuentas y un [] explícito las vacía. dry_run=true siempre devuelve HTTP 200 sin reservar ni consumir filas; import_uuid, el status de ejecución y los contadores son null.
Rellena la plantilla descargada
Descarga la plantilla de contactos con GET /v1/contacts/import/template (contacts:read), conserva sus cabeceras y escribe un contacto por fila de datos. El CSV descargado usa UTF-8 con BOM y comas. Si conviertes la plantilla a XLSX, conserva sus cabeceras originales. Sube el archivo rellenado, revisa la correspondencia de columnas y previsualiza las filas antes de aplicar la importación.
Una plantilla que sólo contiene cabeceras es válida para previsualizar: HTTP devuelve 200, total=0, rows=[] y source_headers en el orden original. Las columnas vacías se conservan, también cuando una hoja no tiene filas de datos. dry_run=true se comporta igual y no crea un registro de importación.
Aplicar un archivo sin filas de datos devuelve HTTP 422: error.code=business_rule_violation, error.subcode=empty_import y error.param=file. Rellena la plantilla y vuelve a intentarlo. No se crea un registro de importación ni se encola trabajo. Las herramientas MCP conservan la misma distinción entre previsualizar y aplicar; estos códigos de estado corresponden a HTTP.
Consulta la importación aceptada
Se cuentan registros CSV lógicos, incluidos los registros entrecomillados con saltos de línea. HTTP ejecuta hasta 199 registros de forma síncrona con 200; 200 o más se aceptan con 202 y queued=true. Ambos caminos devuelven import_uuid. Las respuestas encoladas tienen status=queued y contadores de ejecución null; aceptar no significa que todas las filas hayan terminado. MCP devuelve el mismo payload JSON; 200/202 son códigos del transporte HTTP.
Usa GET /v1/contacts/imports/{id}, pasando el import_uuid recibido como id. Requiere contacts:read y devuelve object=contact_import, entity_type=business_contacts, el estado persistido, contadores y outcomes. La empresa procede de la credencial autenticada. Los UUID de otra empresa, inexistentes o de otro módulo devuelven el mismo 404 import_not_found; sin scope de lectura devuelve 403 insufficient_scope.
| Campo | Significado |
|---|---|
total_rows / total | Registros de origen en GET y en las respuestas de preview/síncronas. El payload inmediato encolado conserva total=0; consulta el total aceptado con GET. |
added_count | Filas aplicadas create, update y add_role confirmadas. |
skipped_count / failed_count | Filas omitidas o rechazadas confirmadas. |
unprocessed_count | Registros de origen sin un resultado confirmado. |
status / failure_reason | Estado persistido real, incluidos los trabajos fallidos que conservan progreso parcial. |
Una importación terminal puede tener status=failed aunque failed_count=0: la infraestructura o el mantenimiento pueden cerrar un trabajo con escrituras confirmadas y filas pendientes. La respuesta síncrona usa ese mismo estado persistido. Su total conserva los registros de origen, pero rows y las categorías incluyen sólo filas confirmadas; cada una incluye result como applied, skipped o failed. Las filas de previsualización omiten result.
Por ejemplo, el mantenimiento cerró esta importación síncrona después de una fila confirmada. La fila pendiente no se presenta como aplicada:
{
"data": {
"rows": [
{
"row": 2,
"action": "create",
"result": "applied",
"target_uuid": "0198f4d1-a492-7e05-9a35-000000000001",
"errors": [],
"warnings": []
}
],
"source_headers": ["name", "tax_id", "roles"],
"total": 2,
"create": 1,
"update": 0,
"add_role": 0,
"merge_candidate": 0,
"conflict": 0,
"invalid": 0,
"dry_run": false,
"queued": false,
"import_uuid": "0198f4d1-a492-7e05-9a35-000000000201",
"added_count": 1,
"skipped_count": 0,
"failed_count": 0,
"unprocessed_count": 1,
"status": "failed",
"failure_reason": "stale_timeout"
}
}Descarga los diagnósticos originales
GET /v1/contacts/imports/{id}/errors.csv requiere contacts:read y devuelve bytes CSV UTF-8 con BOM y las cabeceras row_number,field,code,message. Conserva la coordenada del origen: CSV usa el número de registro lógico con cabecera=1; las hojas de cálculo usan el índice físico de fila. Un informe ausente devuelve 404 import_not_found.
Los informes están disponibles para importaciones terminales durante la retención configurada, 90 días por defecto. El estado deja de anunciar error_report_url al vencer, incluso antes de la limpieza física. Si falta el CSV o no se puede leer, los diagnósticos confirmados lo reconstruyen sin escribir otro archivo. Las importaciones sin diagnósticos de fila no tienen informe de errores.
En MCP, usa get_contact_import para consultar el progreso y download_contact_import_errors para recibir id, filename, mime_type, hash y file_base64. Ambos requieren contacts:read; los bytes descodificados coinciden con HTTP y hash es SHA-256. Las descargas requieren autenticación y no generan URL anónimas.
Cuota mensual de filas
Las nuevas admisiones de contactos comparten la cuota mensual de filas de importación del plan. Las filas aplicadas create, update y add_role la consumen; las omitidas, rechazadas y pendientes no. Las reservas concurrentes protegen la cuota antes de escribir o encolar. Las importaciones admitidas bajo la exención anterior de contactos la conservan.
Una cuota agotada devuelve HTTP 429 import_row_quota_exceeded, con tipo de error rate_limit_error, antes de escribir contactos o encolar. Esta cuota es independiente de los bytes subidos y de los límites de peticiones HTTP.