Saltar al contenido principal

Importar un CSV a una lista

POST/v1/lists/{id}/imports

Para 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​

201 CreatedDevuelve el objeto creado. El header 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}. null mientras la lista no declara sus columnas.
statusstring, enum: `awaiting_mapping | pending | processing | completed | failed`siempre presente
awaiting_mapping mientras la lista no declara sus columnas, pending mientras espera su turno, processing mientras se lee el archivo, y completed o failed al 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. null hasta que se procesa.
imported_row_countinteger | null
Filas que quedaron en la lista. 0 si 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, zip o 7z. No están en una combinación ni en una instantánea.
source
En una instantánea: dataset_id, el dataset leído, y snapshot_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_value o duplicated.
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 tiene repair_encoding, o detectadas y cargadas tal cual si no.
error
Si la importación falló: code, y field o line cuando 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 trae list_id e import_id, que es la importación de la que salieron sus datos. null en 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, PHONE o UNIQUECODE. null en 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, update o replace. null en 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. null en 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.
Notas
  • Mismos campos que GET /v1/lists/{id}/imports/{import_id}.
  • La importación nace en estado pending, o awaiting_mapping si la lista todavía no declara columnas. job_id es el trabajo que la ejecuta, que se consulta en GET /v1/jobs/{id}; es null en awaiting_mapping, hasta que se declaran las columnas.

Errores​

CódigoCuándo
404La lista no existe o fue eliminada (list_not_found).
409La 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).
413El archivo supera los 200 MB (request_too_large).
422Falta file, o delimiter no es uno de los admitidos. También con errors[].code propio en /file, detallado abajo.
503No se pudo guardar el archivo o dejar la importación en cola (service_unavailable). No queda nada registrado: reintente.

Errores de /file (422):

errors[].codeCuándo
list_file_emptyEl archivo, o su contenido una vez descomprimido, está vacío.
list_file_is_spreadsheetEl 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_textEl contenido no es texto: por ejemplo, un PDF o una imagen.
list_file_archive_multipleEl zip o el 7z trae más de un archivo.
list_file_archive_emptyEl zip o el 7z no trae ningún archivo.
list_file_archive_encryptedEl comprimido tiene contraseña.
list_file_archive_corruptEl comprimido está dañado.
list_file_columns_missingA 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.

Notas
  • 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 en GET /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_pos 1. 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.
Request
curl -X POST "https://$API_HOST/v1/lists/4/imports" \
-H "Authorization: Bearer $API_KEY" \
-H "X-Instance-Slug: $SLUG" \
-F "file=@clientes-marzo.csv.gz" \
-F "delimiter=;"
Response
{
"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
}