> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zappway.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API de contactos

> Referencia interna para la API de contactos: CRUD, operaciones masivas, candidatos de fusión, cronograma y vista 360 del cliente.

> **Documentación interna para desarrolladores.** Esta página cubre los puntos finales de la API de contactos, las operaciones masivas, la detección de fusiones y el modelo de datos de cliente 360. No está destinado a usuarios finales.

***

## Mapa de ruta

| Método   | Punto final                      | Archivo de controlador               | Descripción                  |
| -------- | -------------------------------- | ------------------------------------ | ---------------------------- |
| `GET`    | `/api/contacts`                  | `contacts/route.ts`                  | Listar contactos con filtros |
| `POST`   | `/api/contacts`                  | `contacts/route.ts`                  | Crear un contacto            |
| `GET`    | `/api/contacts/[contactId]`      | `contacts/[contactId]/route.ts`      | Obtener contacto por ID      |
| `PATCH`  | `/api/contacts/[contactId]`      | `contacts/[contactId]/route.ts`      | Actualizar contacto          |
| `DELETE` | `/api/contacts/[contactId]`      | `contacts/[contactId]/route.ts`      | Eliminar contacto            |
| `POST`   | `/api/contacts/bulk-delete`      | `contacts/bulk-delete/route.ts`      | Eliminar varios contactos    |
| `GET`    | `/api/contacts/merge-candidates` | `contacts/merge-candidates/route.ts` | Buscar candidatos duplicados |

***

## Patrón de autenticación

```ts theme={null}
withPermissionRoute(req, {
  anyPermission: ['contacts.read'],  // for GET
  // or
  anyPermission: ['contacts.write'], // for mutations
  authMode: 'lightweight',           // for reads
}, handler)
```

Todas las consultas deben tener como alcance `req.session.organization.id`.

***

## Esquema de objeto de contacto

```ts theme={null}
interface Contact {
  id: string;
  organizationId: string;
  name: string | null;
  email: string | null;
  phone: string | null;
  whatsappPhone: string | null;
  externalId: string | null;
  avatarUrl: string | null;
  metadata: Record<string, unknown>;
  tags: string[];
  createdAt: string;
  updatedAt: string;
}
```

***

## Listar contactos (filtros)

```ts theme={null}
// GET /api/contacts
// Query params:
// - search: string (name, email, phone, externalId)
// - page, limit: pagination
// - tag: string (filter by tag)
// - channel: string (contacts with conversations in this channel)
// - dateFrom, dateTo: ISO 8601
```

***

## Eliminación masiva

```ts theme={null}
// POST /api/contacts/bulk-delete
// Body: { contactIds: string[] }
// Deletes all contacts + cascades to conversations
// Max batch: 100 IDs per request (to prevent timeout)
```

***

## Fusionar candidatos

El punto final `merge-candidates` ejecuta un algoritmo de coincidencia aproximada para identificar posibles contactos duplicados:

```ts theme={null}
// GET /api/contacts/merge-candidates?contactId=xxx
// Returns contacts that match by email, phone, or name similarity
// Uses: Prisma + application-level fuzzy matching
```

**Estrategia de fusión:**

* El contacto principal mantiene su identificación.
* Se reatribuyen las conversaciones del contacto secundario.
* Se elimina el contacto secundario.
* **No deshacer**: advierte a los usuarios antes de fusionar

***

## Cliente-Vista 360

La página de contacto individual agrega datos de múltiples fuentes:

| Fuente                                       | Datos                                       |
| -------------------------------------------- | ------------------------------------------- |
| `Contact` tabla                              | Perfil central                              |
| `Conversation` tabla                         | Todas las conversaciones                    |
| `Message` tabla (a través de conversaciones) | Historial de mensajes                       |
| `metadata` JSON                              | Campos personalizados                       |
| Webhooks de integración                      | CRM/datos externos (si están sincronizados) |

***

## Índices Prisma utilizados

| Mesa      | Índice                       | Utilizado por                      |
| --------- | ---------------------------- | ---------------------------------- |
| `Contact` | `organizationId`             | Todas las consultas de lista       |
| `Contact` | `organizationId, email`      | Fusionar detección de candidatos   |
| `Contact` | `organizationId, phone`      | Fusionar detección de candidatos   |
| `Contact` | `organizationId, externalId` | Sincronización del sistema externo |

***

## Problemas conocidos / Problemas

* **Cascada de eliminación masiva:** Al eliminar contactos, se eliminan sus conversaciones. Esta es una operación destructiva. Confirme siempre con el usuario antes de llamar.
* **Normalización de teléfonos:** Los números de teléfono deben almacenarse en formato E.164 (`+5511999990000`). Los formatos inconsistentes hacen que los candidatos a fusión omitan duplicados.
* **`externalId`** se usa para la sincronización de CRM (por ejemplo, HubSpot, Salesforce). Al sincronizar desde sistemas externos, utilice siempre `upsert` en `organizationId + externalId`.
* **Fusionar candidatos** utiliza coincidencias a nivel de aplicación (no a nivel de base de datos). Para listas de contactos grandes (más de 100.000), esto puede resultar lento. Considere agregar un trabajo en segundo plano para organizaciones grandes.
