Skip to main content
POST

Descripción

Este endpoint hace un upsert: identifica al contacto por su número de teléfono dentro de la compañía asociada a tu Company API Key y, si existe lo actualiza, si no lo crea. Es la operación recomendada para sincronizar contactos desde un sistema externo, porque no necesitás conocer el id interno de Mindo ni hacer dos llamadas. Si ya tenés el id, usá actualizar contacto. La operación es atómica: si el teléfono, un dato de perfil o cualquier campo personalizado es inválido, no se guarda ningún cambio del request.
El endpoint devuelve 201 cuando creó el contacto y 200 cuando actualizó uno existente. El cuerpo es el mismo en ambos casos: revisá el campo created para saber cuál fue.

Cómo se identifica el contacto

El número que enviás en phone se normaliza a E.164 antes de buscar, y la búsqueda admite las mismas variantes que el endpoint de consulta: E.164 con o sin +, formatos internacionales de Meta y, para Argentina, las variantes con 9 y con 15. Todas estas llamadas resuelven al mismo contacto:
Un contacto creado por este endpoint se guarda con el número ya normalizado a E.164, para que las siguientes llamadas lo encuentren de forma unívoca.
Si el número no normaliza a un E.164 válido, la llamada devuelve 400 y no se crea nada. Enviá el teléfono con código de país; no se asume ninguna región por vos salvo Argentina.

Lista de contactos destino

Al crear, el contacto va a la lista por defecto de tu compañía. Si querés otra, enviá contact_list_id. Al actualizar, el contacto permanece en su lista actual. contact_list_id sólo se acepta si coincide con esa lista; enviar una distinta devuelve 400 en vez de mover el contacto. Este endpoint no migra contactos entre listas.
Si tu compañía no tiene una lista marcada como predeterminada, contact_list_id pasa a ser obligatorio al crear.

Header de autenticación

string
requerido
Una Company API Key activa. No se admiten API keys legacy, JWT ni keys globales.
string
requerido
Debe ser application/json.

Campos del body

string
requerido
Número de teléfono del contacto. Es la identidad de la operación: determina si se crea o se actualiza. Debe normalizar a un E.164 válido.
integer
Lista de contactos destino, sólo al crear. Si lo omitís, se usa la lista por defecto de tu compañía. Debe pertenecer a tu compañía.
string | null
Nombre completo del contacto.
string | null
Email del contacto. Puede ser una cadena vacía. Si se informa, debe ser válido.
string
predeterminado:"api"
Origen del contacto. Valores válidos: manual, csv_import, organic, whatsapp_sync, instagram_sync, google_contacts, group, api y other. Si lo omitís al crear, queda en api.
string | null
Detalle del origen. Puede ser una cadena vacía.
string (URL) | null
URL de la foto de perfil. Puede ser una cadena vacía.
array
Campos personalizados que querés crear o actualizar.
No podés modificar el id, la lista de un contacto existente, identificadores de WhatsApp o Instagram, fechas ni flags internos. Enviar cualquiera de estos campos, o cualquier campo fuera de la lista de arriba, devuelve 400. El teléfono tampoco es editable: es la clave con la que se identifica al contacto, no un dato que se pueda cambiar por esta vía.

Identificar campos personalizados

Cada elemento de custom_fields debe traer value y exactamente uno de custom_field_id o key. Enviar los dos, o ninguno, devuelve 400. Recomendamos key: es estable, legible y no depende de IDs internos, lo que hace el payload portable entre entornos.
Podés obtener ambos identificadores del arreglo customFields que devuelve esta misma llamada: el id y la key de cada elemento. Reglas de validación:
  • El campo debe pertenecer a la lista del contacto.
  • No repitas el mismo campo en un request, ni siquiera identificándolo de las dos maneras.
  • Se valida el tipo y las opciones configuradas para cada campo. Los tipos disponibles son string, text, textarea, int, float, email, url, date, datetime, time, selector y multiselector.
  • Los campos que pertenecen a un grupo (formularios repetibles, como turnos) no se pueden asignar por esta API: requieren una instancia de grupo.

Semántica de actualización

La actualización es un merge parcial. Enviá solamente lo que querés cambiar:
  • Los campos de perfil ausentes del payload conservan su valor.
  • Los campos personalizados que no enviás conservan su valor activo.
  • Un campo personalizado cuyo valor y vencimiento no cambian no genera una versión nueva.
Cada campo personalizado que sí cambia crea una versión nueva y conserva el historial. La respuesta enumera esos cambios en versionedCustomFields.

Idempotencia y concurrencia

La operación es idempotente respecto del teléfono: repetir el mismo request no crea contactos duplicados ni versiones nuevas de campos personalizados que no cambiaron. Dos llamadas concurrentes con el mismo número se serializan a nivel base de datos: la segunda espera a la primera y actualiza el contacto que ésta creó, en lugar de crear un duplicado.

Convención de nombres de campos

En el request, los campos de primer nivel se aceptan tanto en snake_case (full_name) como en camelCase (fullName).
La excepción es el contenido de custom_fields: ahí las claves se leen literalmente. Enviá custom_field_id y expires_at en snake_case. Un customFieldId se ignora y la llamada falla con 400.
En la respuesta, las claves de primer nivel se devuelven en camelCase (fullName, contactListId, customFields, versionedCustomFields, customFieldId), mientras que dentro de cada elemento de customFields se conservan en snake_case (field_type, expires_at).

Respuesta (201 Created / 200 OK)

boolean
true si se creó el contacto en esta llamada, false si se actualizó uno existente. Acompaña al código de estado: 201 y 200 respectivamente.
object
Contacto resultante, con todos los campos personalizados configurados en su lista.
array
Campos personalizados que generaron una versión nueva en esta llamada. Puede ser una lista vacía si ningún valor ni vencimiento cambió.

Errores

Ante un 409, resolvé la duplicidad de contactos antes de continuar. La API no actualiza ni selecciona un contacto de forma arbitraria.

Ejemplos de error

Las claves de error de campos personalizados son la posición del elemento dentro del arreglo custom_fields que enviaste, empezando en "0".

Recomendaciones de integración

1

Usá el upsert como operación por defecto

Para sincronizar contactos desde tu sistema, este endpoint reemplaza al par consulta + actualización. Es idempotente por teléfono y no depende de IDs internos de Mindo.
2

Identificá los campos personalizados por key

La key es estable y legible, y hace que el mismo payload funcione en cualquier entorno. Si preferís los IDs numéricos, guardalos por compañía y lista en vez de deducirlos del nombre del campo.
3

Enviá sólo lo que cambió

El merge parcial evita versiones innecesarias en el historial de campos personalizados y hace las llamadas más livianas.
4

Registrá el resultado, no sólo el código

Guardá created y versionedCustomFields para auditar qué hizo realmente cada sincronización.
5

Tratá el 409 como una alerta operativa

Un 409 significa que tu compañía tiene contactos duplicados en Mindo. No es un error transitorio: reintentarlo no lo resuelve.
Guardá tu API Key como secreto. No la incluyas en código de cliente, repositorios ni logs, y filtrá el header X-API-Key de cualquier traza que registres.

Siguientes pasos

Buscar contacto

Consultá un contacto por teléfono y revisá si respondió y si la ventana de sesión está activa.

Actualizar contacto

Actualizá un contacto cuando ya conocés su ID interno.