# Sincronizar contactos desde tu sistema

> Mantén tus contactos de MINDO al día con los clientes de tu tienda o CRM, con atributos para segmentar.

Si tus clientes viven en otro sistema (tu tienda online, un CRM, un ERP, una planilla que se actualiza sola), puedes copiarlos a MINDO con la API. Así armas [segmentos](/guias/contactos/segmentos) con datos siempre frescos: _“compraron en los últimos 30 días”_, _“viven en Córdoba”_, _“clientes VIP”_.

## Cómo funciona `POST /contacts`

Un solo endpoint crea o actualiza, según si el teléfono ya existe:

```bash
curl -X POST https://app.mindo.ar/api/v1/contacts \
  -H "Authorization: Bearer $MINDO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+52 55 1234 5678",
    "name": "Ximena Robles",
    "attributes": { "ciudad": "Ciudad de México", "categoria": "VIP", "ultima_compra": "2026-09-20" }
  }'
```

- **Responde `201`** si lo creó y **`200`** si ya existía y lo actualizó.
- **`attributes` se combina**: solo cambian las claves que mandas; el resto queda igual.
- **`name` solo cambia si lo mandas.** Si no lo incluyes, queda como estaba.
- Un atributo que todavía no existe se crea como [campo](/guias/contactos/campos) de texto. Desde ese momento puedes filtrar por él y usarlo como variable en tus plantillas.

<Warning>
  Los valores de `attributes` siempre son texto: manda `"45000"`, no `45000`. Si el campo es de tipo número o fecha en **Contactos › Campos**, MINDO lo convierte al guardarlo. Para fechas, usa `AAAA-MM-DD`.
</Warning>

## Carga inicial

Recorre tus clientes y manda uno por uno. Es seguro volver a correrlo: los que ya existen solo se actualizan.

<CodeGroup>

```javascript Node
const MINDO = "https://app.mindo.ar/api/v1"
const headers = {
  Authorization: `Bearer ${process.env.MINDO_API_KEY}`,
  "Content-Type": "application/json",
}

async function sincronizar(cliente) {
  const res = await fetch(`${MINDO}/contacts`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      phone: cliente.telefono,
      name: `${cliente.nombre} ${cliente.apellido}`.trim(),
      attributes: {
        ciudad: cliente.ciudad ?? "",
        total_gastado: String(cliente.totalGastado),
        ultima_compra: cliente.ultimaCompra?.slice(0, 10) ?? "",
      },
    }),
  })
  if (res.status === 402) throw new Error((await res.json()).error) // límite del plan: frena todo
  if (!res.ok) console.warn(`${cliente.telefono}: ${(await res.json()).error}`)
}

const clientes = await obtenerClientesDeMiTienda() // tu código
for (const cliente of clientes) {
  await sincronizar(cliente)
}
```

```python Python
import os, requests

MINDO = "https://app.mindo.ar/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['MINDO_API_KEY']}"

def sincronizar(cliente):
    res = session.post(f"{MINDO}/contacts", json={
        "phone": cliente["telefono"],
        "name": f"{cliente['nombre']} {cliente['apellido']}".strip(),
        "attributes": {
            "ciudad": cliente.get("ciudad") or "",
            "total_gastado": str(cliente["total_gastado"]),
            "ultima_compra": (cliente.get("ultima_compra") or "")[:10],
        },
    })
    if res.status_code == 402:
        raise Exception(res.json()["error"])  # límite del plan: frena todo
    if not res.ok:
        print(f"{cliente['telefono']}: {res.json()['error']}")

for cliente in obtener_clientes_de_mi_tienda():  # tu código
    sincronizar(cliente)
```

</CodeGroup>

<Tip>
  ¿Son muchos miles y es una sola vez? Es más rápido exportarlos a Excel o CSV e [importarlos desde la app](/guias/contactos/importar). Usa la API para mantenerlos al día después.
</Tip>

## Mantenerlos al día

Después de la carga inicial, llama a `POST /contacts` cada vez que algo cambia en tu sistema:

- Se registra un cliente nuevo.
- Un cliente hace una compra (actualiza `ultima_compra` y `total_gastado`).
- Cambia de categoría (por ejemplo, pasa a VIP: actualiza el atributo `categoria`).

Si tu plataforma avisa con webhooks (Tiendanube, Shopify y WooCommerce lo hacen), conecta esos avisos a una función como `sincronizar()`.

## Y al revés: de MINDO a tu sistema

- Para traer todos los contactos, recorre `GET /contacts` [página por página](/api/paginacion).
- Para enterarte de los nuevos al instante, suscríbete a [`contact.created`](/api/webhooks/eventos#contact-created).
- Para respetar las bajas en tus otros sistemas, suscríbete a [`contact.opted_out`](/api/webhooks/eventos#contact-opted-out).

## Límite de contactos

Cada plan tiene un máximo de contactos. Si al crear uno nuevo te pasas, la API responde `402` con `cause.reason: "limit"`. Actualizar contactos existentes siempre funciona.
