Clientes
API de Clientes
Endpoints para administrar tu directorio de clientes. Cada cliente tiene un email único por tenant.
Listar Clientes
GET /api/clients
Permiso: clients:read
Obtén una lista paginada de clientes activos del tenant actual.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| search | string | No | Busca por nombre de contacto, nombre de empresa o email (sin distinguir mayúsculas) |
| page | number | No | Número de página (por defecto: 1) |
Response 200 OK:
{
"data": [
{
"id": "clxyz...",
"contactName": "María López",
"companyName": "Distribuidora del Norte S.A.",
"email": "maria@distribuidora.mx",
"phone": "+52 81 1234 5678",
"isActive": true,
"tenantId": "...",
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-15T14:00:00.000Z"
}
],
"total": 45,
"page": 1,
"totalPages": 3
}Ejemplo con cURL:
curl -X GET "https://cotizera.com/api/clients?search=María&page=1" \
-H "Cookie: next-auth.session-token=YOUR_TOKEN"Crear Cliente
POST /api/clients
Permiso: clients:create
Crea un nuevo cliente. El email debe ser único dentro del tenant.
Request Body:
{
"contactName": "Roberto García",
"companyName": "Servicios Industriales MX",
"email": "roberto@servindustrial.mx",
"phone": "+52 55 9876 5432"
}| Field | Type | Required | Description |
|---|---|---|---|
| contactName | string | Yes | Nombre de la persona de contacto (mínimo 1 carácter) |
| companyName | string | No | Nombre de la empresa o negocio |
| string | Yes | Dirección de email válida (única por tenant) | |
| phone | string | No | Número de teléfono |
Response 201 Created: Devuelve el objeto del cliente creado.
Errores:
| Status | Error | Cuándo |
|---|---|---|
| 400 | Mensaje de validación Zod | Entrada inválida |
| 401 | "No autorizado" | Sesión ausente o inválida |
| 403 | "Sin permisos" | El rol no tiene clients:create |
| 409 | "Ya existe un cliente con ese correo" | Email duplicado en el tenant |
Efectos secundarios:
- Dispara el evento webhook
client.created - Activa el paso de onboarding
first_client - Registra una entrada de auditoría con acción
create
Obtener un Cliente
GET /api/clients/:id
Permiso: clients:read
Obtén un cliente activo individual. Opcionalmente puedes incluir su historial de cotizaciones.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| includeQuotes | string | No | Establece "true" para incluir las cotizaciones del cliente |
Response 200 OK (con includeQuotes=true):
{
"id": "clxyz...",
"contactName": "María López",
"companyName": "Distribuidora del Norte S.A.",
"email": "maria@distribuidora.mx",
"phone": "+52 81 1234 5678",
"quotes": [
{
"id": "...",
"quoteNumber": 42,
"status": "WON",
"total": "17900.00",
"createdAt": "2026-03-31T10:00:00.000Z",
"_count": { "items": 3 }
}
]
}Errores:
| Status | Error | Cuándo |
|---|---|---|
| 404 | "Cliente no encontrado" | Cliente no encontrado, inactivo o de otro tenant |
Actualizar Cliente
PUT /api/clients/:id
Permiso: clients:update
Actualiza la información de un cliente existente. Si se cambia el email, se vuelve a validar la unicidad.
Request Body: Mismo esquema que Crear Cliente.
Response 200 OK: Devuelve el objeto del cliente actualizado.
Errores:
| Status | Error | Cuándo |
|---|---|---|
| 404 | "Cliente no encontrado" | Cliente no encontrado o inactivo |
| 409 | "Ya existe un cliente con ese correo" | El nuevo email entra en conflicto con otro cliente existente |
Eliminar Cliente (Soft Delete)
DELETE /api/clients/:id
Permiso: clients:delete
Elimina un cliente de forma lógica estableciendo isActive en false. Los datos del cliente se conservan pero se excluyen de los listados.
Response 200 OK:
{
"success": true
}Errores:
| Status | Error | Cuándo |
|---|---|---|
| 404 | "Cliente no encontrado" | Cliente no encontrado o ya está inactivo |