Importar un CSV a una lista
/v1/lists/{id}/importsPara desarrolladores
Descripción
Sube el archivo de una lista. La importación queda en cola y la respuesta llega antes de que
se lean sus filas: consulte después el estado en la URL del header Location
(GET /v1/lists/{id}/imports/{import_id}).
Una lista recibe sus datos una sola vez, de un archivo, de una combinación de otras listas
(POST /v1/lists/merge) o de una instantánea de un dataset
(POST /v1/datasets/{id}/snapshot). Una vez cargada, no admite
otro archivo ni cambios en sus columnas: para cargar un archivo nuevo, cree una lista nueva.
Si la importación falla, la lista queda sin datos y acepta el archivo corregido.
Cada columna del archivo se interpreta según las columnas declaradas de la lista
(PUT /v1/lists/{id}/fields), por su posición. Las primeras líneas
quedan como vista previa de la lista (GET /v1/lists/{id}/preview).
Las columnas se pueden declarar antes o después de subir el archivo. Si la lista todavía no
las declara, la importación queda en awaiting_mapping: la vista previa propone un campo
para cada columna, y la importación queda en cola cuando se declaran las columnas. Si sube
otro archivo mientras tanto, el nuevo reemplaza al anterior.
Autenticación
Authorizationbearer tokenheaderobligatorio- API key con scope
list:write. Formato:Bearer <API_KEY>. X-Instance-Slugstringheaderobligatorio- Identificador de su instancia. Ver Autenticación.
Request
Path params:
idintegerobligatorio- Identificador de la lista.
Body (multipart/form-data):
filefileobligatorio- El CSV, plano o comprimido en gzip, zip o 7z. Hasta 200 MB (209 715 200 bytes), comprimido o no.
delimiterstring, enum: `, | ; | \t | |`- Separador de columnas. Si se omite, se detecta en las primeras líneas.
El archivo:
- Formato: un CSV, o un CSV comprimido en gzip, zip o 7z. El formato se reconoce por el contenido, no por la extensión. Un zip o un 7z tiene que traer un solo archivo, y no puede tener contraseña.
- Codificación: UTF-8 (con o sin BOM), UTF-16 con BOM, o ISO-8859-1 / Windows-1252, que es la que usa Excel en español al guardar como "CSV (delimitado por comas)". Se detecta sola, sobre el archivo completo, y los datos se guardan en UTF-8.
- Separador: coma, punto y coma, tabulación o barra vertical (
|). - Cabecera: la primera línea es la cabecera y no se importa. Si la lista ya declara sus columnas, la cabecera tiene que tenerlas todas.
- Celdas con apóstrofo: si una celda empieza con un apóstrofo seguido de
=,+,-o@, la importación quita ese apóstrofo. Es el que agrega toda exportación CSV de la plataforma, así que un archivo exportado y vuelto a subir conserva sus valores. - Un archivo de Excel (
.xlsx) no es un CSV, aunque se le cambie la extensión: guárdelo como CSV desde Excel.
Response
Location trae su URL (ver Headers).idintegersiempre presente- Identificador de la importación.
list_idintegersiempre presente- Lista a la que pertenece.
job_idstring (UUID) | null- Trabajo que ejecuta la importación; su estado se consulta en
GET /v1/jobs/{id}.nullmientras la lista no declara sus columnas. statusstring, enum: `awaiting_mapping | pending | processing | completed | failed`siempre presenteawaiting_mappingmientras la lista no declara sus columnas,pendingmientras espera su turno,processingmientras se lee el archivo, ycompletedofailedal terminar.file_namestring | null- Nombre que tenía el archivo al subirlo.
file_bytesinteger | null- Tamaño del archivo tal como se subió, en bytes.
encodingstring | null- Codificación del archivo: la detectada en sus primeras líneas hasta que se procesa, y después la que se decidió sobre el archivo completo (
utf-8,utf-16,utf-32,cp1252). delimiterstring | null- Separador de columnas: el indicado al subirlo o el detectado.
csv_row_countinteger | null- Filas leídas del archivo, sin contar la cabecera ni las filas en blanco. En una combinación, las leídas de las listas; en una instantánea, las del dataset.
nullhasta que se procesa. imported_row_countinteger | null- Filas que quedaron en la lista.
0si la importación falló. failed_row_countinteger | null- Filas descartadas por un valor inválido, un campo obligatorio vacío, columnas de más o caracteres que no corresponden a la codificación.
duplicated_row_countinteger | null- Filas descartadas por repetir el valor de una columna única. En una combinación, las de un contacto que ya estaba en una lista anterior; en una instantánea, las filas más antiguas de un contacto que el dataset tiene repetido.
has_rejectsbooleansiempre presente- Si hay un archivo con las filas descartadas para descargar (
GET /v1/lists/{id}/imports/{import_id}/rejects). error_messagestring | null- Por qué falló la importación, si falló (en inglés).
diagnosticsobject | null- Detalle de la importación, descrito abajo.
encoding, format- La codificación con que se leyó el archivo y su formato:
plain,gzip,zipo7z. No están en una combinación ni en una instantánea. source- En una instantánea:
dataset_id, el dataset leído, ysnapshot_at, el momento en que se leyó (UTC). reasons- Filas descartadas por motivo. Cada fila cuenta una vez, con el primer motivo que encontró:
invalid_character,extra_columns,required_missing,invalid_valueoduplicated. fields- Por
field_key, cuántas filas tenían ese campo vacío siendo obligatorio, inválido o repetido. Una fila con dos campos inválidos cuenta en los dos. repaired_rows / damaged_text_rows- Filas con texto dañado por una conversión de codificación anterior (
José): reparadas si la lista tienerepair_encoding, o detectadas y cargadas tal cual si no. error- Si la importación falló:
code, yfieldolinecuando el problema tiene un lugar en el archivo.
source_listsobject[] | null- En una combinación (
POST /v1/lists/merge), las listas que se combinaron, en orden. Cada una traelist_ideimport_id, que es la importación de la que salieron sus datos.nullen una importación de archivo o en una instantánea. identity_fieldstring | null- En una combinación o en una instantánea, el campo que identifica a un contacto:
EMAIL,PHONEoUNIQUECODE.nullen una importación de archivo. collision_policystring | null- En una combinación, cómo se resolvió un contacto que estaba en varias listas:
discard,fill,updateoreplace.nullen una importación de archivo o en una instantánea. delete_sourcesboolean | null- En una combinación, si las listas de origen se eliminan al terminar.
nullen una importación de archivo o en una instantánea. created_atstring (date-time)siempre presente- Cuándo se subió el archivo (ISO 8601, UTC).
started_atstring (date-time) | null- Cuándo empezó a leerse.
finished_atstring (date-time) | null- Cuándo terminó, haya completado o fallado.
- Mismos campos que
GET /v1/lists/{id}/imports/{import_id}. - La importación nace en estado
pending, oawaiting_mappingsi la lista todavía no declara columnas.job_ides el trabajo que la ejecuta, que se consulta enGET /v1/jobs/{id}; esnullenawaiting_mapping, hasta que se declaran las columnas.
Errores
| Código | Cuándo |
|---|---|
| 404 | La lista no existe o fue eliminada (list_not_found). |
| 409 | La lista salió de una instantánea de un dataset y solo recibe datos de él (list_is_snapshot), ya recibió sus datos (list_has_data), o tiene una importación pendiente o en curso (list_import_in_progress). |
| 413 | El archivo supera los 200 MB (request_too_large). |
| 422 | Falta file, o delimiter no es uno de los admitidos. También con errors[].code propio en /file, detallado abajo. |
| 503 | No se pudo guardar el archivo o dejar la importación en cola (service_unavailable). No queda nada registrado: reintente. |
Errores de /file (422):
errors[].code | Cuándo |
|---|---|
list_file_empty | El archivo, o su contenido una vez descomprimido, está vacío. |
list_file_is_spreadsheet | El archivo es una planilla (.xlsx, .xlsm, .xls, .ods), aunque se suba con otro nombre: se reconoce por su contenido. Guárdela como CSV y súbala de nuevo. |
list_file_not_text | El contenido no es texto: por ejemplo, un PDF o una imagen. |
list_file_archive_multiple | El zip o el 7z trae más de un archivo. |
list_file_archive_empty | El zip o el 7z no trae ningún archivo. |
list_file_archive_encrypted | El comprimido tiene contraseña. |
list_file_archive_corrupt | El comprimido está dañado. |
list_file_columns_missing | A la cabecera, leída con el separador detectado o con el indicado en delimiter, le falta la columna de algún campo declarado. errors[].params trae delimiter, columns (las columnas que encontró), fields (los campos que quedaron fuera) y, si la cabecera parece usar otro separador, suggested_delimiter. |
Un separador equivocado se detecta acá, al subir el archivo: la cabecera se lee como una sola columna, y los campos declarados en las posiciones siguientes no encuentran su columna. Vuelva a subir el archivo
con delimiter igual a suggested_delimiter.
Detalle completo en Errores genéricos.
- Una fila con un problema no detiene la importación: se descarta y queda en el archivo de
rechazos (
GET /v1/lists/{id}/imports/{import_id}/rejects). La importación falla solo por un problema del archivo entero; los casos están enGET /v1/lists/{id}/imports/{import_id}. - Las columnas se leen por posición: la primera columna del archivo es la que se declaró
con
csv_pos1. Las columnas sin campo declarado se ignoran. - El tamaño máximo se aplica al archivo tal como se sube. Lo que pesa una vez descomprimido no tiene un tope propio.
curl -X POST "https://$API_HOST/v1/lists/4/imports" \
-H "Authorization: Bearer $API_KEY" \
-H "X-Instance-Slug: $SLUG" \
-F "[email protected]" \
-F "delimiter=;"
{
"id": 17,
"list_id": 4,
"job_id": "01a13a48-9e05-7d41-9a8f-3c1d2e4f5a6b",
"status": "pending",
"file_name": "clientes-marzo.csv.gz",
"file_bytes": 182344,
"encoding": "utf-8",
"delimiter": ";",
"csv_row_count": null,
"imported_row_count": null,
"failed_row_count": null,
"duplicated_row_count": null,
"has_rejects": false,
"error_message": null,
"diagnostics": null,
"source_lists": null,
"identity_field": null,
"collision_policy": null,
"delete_sources": null,
"created_at": "2026-10-14T12:00:00Z",
"started_at": null,
"finished_at": null
}