Back to API DocsVolver a Docs API

CRM Relay API Documentation

Documentación API CRM Relay

Simple JWT-authenticated API for lead management

API simple con autenticación JWT para gestión de leads

📋 View cURL Examples 📋 Ver Ejemplos cURL

Quick Reference

Referencia Rápida

The CRM API allows providers to create and view leads, while clients can update lead status. All endpoints use JWT authentication.

La API CRM permite a los proveedores crear y ver leads, mientras que los clientes pueden actualizar el estado. Todos los endpoints usan autenticación JWT.

✨ Key Features

✨ Características Principales

Quickstart Guide

Guía de Inicio Rápido

Get started with the CRM Relay API in 5 simple steps:

Comienza con la API CRM Relay en 5 pasos simples:

  1. Authenticate — Obtain JWT via POST /api/auth/login
  2. Extract Token — Use response.data.token (nested inside data)
  3. Set Header — Add Authorization: Bearer <token> to all requests
  4. Submit Leads — Send to POST /api/crm/leads with required fields
  5. Process Async — System responds 202 and queues for background processing
  1. Autenticar — Obtén JWT via POST /api/auth/login
  2. Extraer Token — Usa response.data.token (anidado dentro de data)
  3. Configurar Header — Agrega Authorization: Bearer <token> a todas las peticiones
  4. Enviar Leads — Envía a POST /api/crm/leads con campos requeridos
  5. Procesamiento Async — El sistema responde 202 y encola para procesamiento en segundo plano

Example: Create Lead

Ejemplo: Crear Lead

curl -X POST "http://localhost/paqueteriacz/api/crm/leads" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \
  -d '{"lead":{"proveedor_lead_id":"PR-001","nombre":"Juan Pérez","telefono":"+50512345678","fecha_hora":"2025-01-15 10:00:00"}}'

Response (202 Accepted)

Respuesta (202 Accepted)

{
    "success": true,
    "message": "Lead(s) aceptado(s) para procesamiento",
    "accepted": 1,
    "inbox_id": 123
}

Authentication

Autenticación

All CRM endpoints require JWT authentication. Use the token from POST /api/auth/login.

Todos los endpoints CRM requieren autenticación JWT. Usa el token de POST /api/auth/login.

Step 1: Login to Get JWT Token

Paso 1: Login para Obtener Token JWT

Authenticate with your credentials to receive a JWT token:

Autentícate con tus credenciales para recibir un token JWT:

POST /api/auth/login

Request Body

Cuerpo de la Petición

{
    "email": "proveedor@example.com",
    "password": "your_secure_password"
}

Response — Success 200

{
    "success": true,
    "message": "Login exitoso",
    "data": {
        "id": "123",
        "nombre": "Usuario Proveedor",
        "email": "proveedor@example.com",
        "rol": "Proveedor",
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEyMyIsIm5vbWJyZSI6IlVzdWFyaW8gUHJvdmVlZG9yIiwiZW1haWwiOiJwcm92ZWVkb3JAZXhhbXBsZS5jb20iLCJyb2wiOiJQcm92ZWVkb3IiLCJleHAiOjE3MDQ4MTI0MDB9.signature_here"
    }
}
Important: The token is nested inside data.token, not at the root level. Extract it as: response.data.token
Importante: El token está anidado dentro de data.token, no en el nivel raíz. Extráelo como: response.data.token

Response — Invalid Credentials 401

{
    "success": false,
    "message": "Credenciales inválidas"
}

Example: Full Login Flow

Ejemplo: Flujo Completo de Login

# Login and extract token
curl -X POST "http://localhost/paqueteriacz/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"proveedor@example.com","password":"your_password"}'

# Response contains token at data.token
# Use it in subsequent requests:
curl -X GET "http://localhost/paqueteriacz/api/crm/leads" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLC..."

Step 2: Use Token in API Requests

Paso 2: Usar Token en Peticiones API

Required Header

Encabezado Requerido

Authorization: Bearer <JWT_TOKEN>

Roles & Permissions

Roles y Permisos

RolePermissions
ProveedorCreate leads, view own leads
ClienteUpdate lead status (ownership required), view assigned leads
AdministradorFull access + system metrics
RolPermisos
ProveedorCrear leads, ver propios leads
ClienteActualizar estado de lead (requiere propiedad), ver leads asignados
AdministradorAcceso completo + métricas del sistema

Create Leads

Crear Leads

Submit individual leads or batches. Returns 202 Accepted immediately.

Envía leads individuales o en lote. Retorna 202 Accepted inmediatamente.

Endpoint

Endpoint

POST /api/crm/leads

Allowed Roles

Roles Permitidos

Proveedor, Administrador

Request — Individual Lead

Request — Lead Individual

{
    "lead": {
        "proveedor_lead_id": "PR-12345",
        "nombre": "Juan Pérez",
        "telefono": "+50512345678",
        "producto": "Laptop Dell",
        "precio": 500.00,
        "fecha_hora": "2025-01-15 10:30:00",
        "cliente_id": 5
    }
}

Request — Batch

Request — Lote

{
    "leads": [
        {"proveedor_lead_id":"PR-001","nombre":"Lead 1","telefono":"+50511111111","fecha_hora":"2025-01-15 10:00:00"},
        {"proveedor_lead_id":"PR-002","nombre":"Lead 2","telefono":"+50522222222","fecha_hora":"2025-01-15 10:05:00"}
    ]
}

Field Reference

Referencia de Campos

FieldTypeRequiredDescription
proveedor_lead_idstring(120)✅ YesUnique lead ID (per provider)
fecha_horadatetime✅ YesLead timestamp (YYYY-MM-DD HH:MM:SS)
nombrestring(255)NoProspect name
telefonostring(30)NoPhone number
productostring(255)NoProduct of interest
preciodecimal(10,2)NoProduct price
cliente_idintegerNoClient ID (auto-forward if has webhook)
CampoTipoRequeridoDescripción
proveedor_lead_idstring(120)✅ SíID único de lead (por proveedor)
fecha_horadatetime✅ SíFecha y hora del lead (YYYY-MM-DD HH:MM:SS)
nombrestring(255)NoNombre del prospecto
telefonostring(30)NoNúmero de teléfono
productostring(255)NoProducto de interés
preciodecimal(10,2)NoPrecio del producto
cliente_idintegerNoID del cliente (auto-reenvío si tiene webhook)

Response — Success 202

{
    "success": true,
    "message": "Lead(s) aceptado(s) para procesamiento",
    "accepted": 1,
    "inbox_id": 123
}

Response — Duplicate (Idempotent) 200

{
    "success": true,
    "message": "Lead(s) ya procesado(s) previamente",
    "accepted": 1,
    "duplicated": true
}

Update Lead Status

Actualizar Estado de Lead

Update lead state with automatic normalization. Clients have full flexibility to change to any valid state.

Actualiza el estado del lead con normalización automática. Clientes tienen total flexibilidad para cambiar a cualquier estado válido.

Endpoint

Endpoint

POST /api/crm/leads/{id}/estado

Allowed Roles

Roles Permitidos

Cliente (owner only), Administrador

Cliente (solo propietario), Administrador

Request Body

Cuerpo de la Petición

{
    "estado": "Aprovado",
    "observaciones": "Cliente confirmó recepción"
}

Valid States & Aliases

Estados Válidos y Alias

Canonical StateAccepted Aliases
EN_ESPERAESPERA, PENDING, WAITING
APROBADOAPROVADO, APPROVED
CONFIRMADOCONFIRMAR, CONFIRMED
EN_TRANSITOEN TRANSITO, TRANSITO, TRANSIT
EN_BODEGAEN BODEGA, BODEGA, WAREHOUSE
CANCELADOCANCELAR, CANCELLED, CANCELED
Estado CanónicoAlias Aceptados
EN_ESPERAESPERA, PENDING, WAITING
APROBADOAPROVADO, APPROVED
CONFIRMADOCONFIRMAR, CONFIRMED
EN_TRANSITOEN TRANSITO, TRANSITO, TRANSIT
EN_BODEGAEN BODEGA, BODEGA, WAREHOUSE
CANCELADOCANCELAR, CANCELLED, CANCELED

State Descriptions

Descripción de Estados

StateDescriptionWhen to Use
EN_ESPERAWaiting for approvalInitial state when order is created
APROBADOApproved and validatedAfter reviewing and approving the order
CONFIRMADOConfirmed with customerCustomer confirmed they want to proceed
EN_TRANSITOPackage on the wayPackage shipped and being transported
EN_BODEGAPackage arrived at warehousePackage received and stored
CANCELADOOrder cancelledOrder will not proceed for any reason
EstadoDescripciónCuándo Usar
EN_ESPERAEsperando aprobaciónEstado inicial cuando se crea el pedido
APROBADOAprobado y validadoDespués de revisar y aprobar el pedido
CONFIRMADOConfirmado con clienteCliente confirmó que procede con el pedido
EN_TRANSITOPaquete en caminoPaquete salió y está siendo transportado
EN_BODEGAPaquete llegó a bodegaPaquete recibido y almacenado
CANCELADOPedido canceladoPedido no procede por cualquier razón
Note: There are no transition restrictions. Clients can change from any state to any other valid state according to their business needs.
Nota: No hay restricciones de transición. Los clientes pueden cambiar de cualquier estado a cualquier otro estado válido según sus necesidades de negocio.

Response — Success 200

{
    "success": true,
    "message": "Estado actualizado a APROBADO",
    "estado_anterior": "EN_ESPERA",
    "estado_nuevo": "APROBADO"
}

Response — Invalid State 400

{
    "success": false,
    "message": "Estado inválido: INVALID_STATE",
    "estados_validos": ["EN_ESPERA", "APROBADO", "CONFIRMADO", "EN_TRANSITO", "EN_BODEGA", "CANCELADO"]
}

Assign Client to Leads

Asignar Cliente a Leads

Assign one or multiple leads to a specific client. Providers can only assign their own leads.

Asigna uno o múltiples leads a un cliente específico. Los proveedores solo pueden asignar sus propios leads.

Endpoint

Endpoint

POST /api/crm/leads/assign-client

Allowed Roles

Roles Permitidos

Proveedor (own leads only), Administrador

Proveedor (solo sus propios leads), Administrador

Request Body

Cuerpo de la Petición

{
    "cliente_id": 5,
    "lead_ids": [101, 102, 103],
    "observaciones": "Asignación manual"
}
FieldTypeRequiredDescription
cliente_idinteger✅ YesTarget Client ID (User ID with role 'Cliente')
lead_idsarray|int✅ YesList of Lead IDs or single ID
observacionesstringNoOptional notes
CampoTipoRequeridoDescripción
cliente_idinteger✅ SíID Cliente Destino (ID Usuario con rol 'Cliente')
lead_idsarray|int✅ SíLista de IDs de Leads o ID único
observacionesstringNoNotas opcionales

Response — Success 200

{
    "success": true,
    "message": "Operación completada. 3 asignados a 'Cliente Juan'.",
    "updated": 3,
    "failed": 0,
    "total_processed": 3
}

Response — Partial Failure 200

{
    "success": true,
    "message": "Operación completada. 2 asignados a 'Cliente Juan'. (1 fallos)",
    "updated": 2,
    "failed": 1,
    "total_processed": 3,
    "failed_details": [
        {"lead_id": 103, "error": "No tienes permiso (No eres el proveedor creador)"}
    ]
}

Bulk Update Lead Status

Actualización Masiva de Estado de Leads

Update the status of multiple leads simultaneously. Clients can only update leads they own (cliente_id), while admins can update any leads.

Actualiza el estado de múltiples leads simultáneamente. Los clientes solo pueden actualizar leads que les pertenecen (cliente_id), mientras que los admins pueden actualizar cualquier lead.

Endpoint

Endpoint

POST /api/crm/leads/bulk-status

Allowed Roles

Roles Permitidos

Cliente (own leads only), Administrador

Cliente (solo sus propios leads), Administrador

Request Body

Cuerpo de la Petición

{
    "lead_ids": [123, 124, 125],
    "estado": "contactado",
    "observaciones": "Contactados vía campaña SMS"
}

Request Fields

Campos de la Petición

FieldTypeRequiredDescription
lead_idsarray of integers✅ YesArray of lead IDs to update (max 100)
estadostring✅ YesNew status (auto-normalized)
observacionesstringNoOptional notes
CampoTipoRequeridoDescripción
lead_idsarray de enteros✅ SíArray de IDs de leads a actualizar (máx 100)
estadostring✅ SíNuevo estado (normalizado automáticamente)
observacionesstringNoNotas opcionales
Ownership Required: Clients can only update leads where cliente_id matches their user ID. Unauthorized leads will fail individually.
Propiedad Requerida: Los clientes solo pueden actualizar leads donde cliente_id coincida con su ID de usuario. Los leads no autorizados fallarán individualmente.

Example cURL

Ejemplo cURL

curl -X POST "http://localhost/paqueteriacz/api/crm/leads/bulk-status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \
  -d '{
    "lead_ids": [123, 124, 125],
    "estado": "aprobado",
    "observaciones": "Procesados el 2026-01-02"
  }'

Response — All Success 200

{
    "success": true,
    "message": "3 de 3 leads actualizados exitosamente",
    "updated": 3,
    "failed": 0,
    "total": 3,
    "estado_nuevo": "APROBADO",
    "results": [
        {
            "lead_id": 123,
            "success": true,
            "estado_anterior": "EN_ESPERA",
            "estado_nuevo": "APROBADO"
        },
        {
            "lead_id": 124,
            "success": true,
            "estado_anterior": "EN_PROCESO",
            "estado_nuevo": "APROBADO"
        },
        {
            "lead_id": 125,
            "success": true,
            "estado_anterior": "EN_ESPERA",
            "estado_nuevo": "APROBADO"
        }
    ]
}

Response — Mixed Results 207 Multi-Status

{
    "success": true,
    "message": "2 de 3 leads actualizados exitosamente",
    "updated": 2,
    "failed": 1,
    "total": 3,
    "estado_nuevo": "APROBADO",
    "results": [
        {
            "lead_id": 123,
            "success": true,
            "estado_anterior": "EN_ESPERA",
            "estado_nuevo": "APROBADO"
        },
        {
            "lead_id": 124,
            "success": false,
            "message": "No tienes permiso para este lead"
        },
        {
            "lead_id": 125,
            "success": true,
            "estado_anterior": "EN_ESPERA",
            "estado_nuevo": "APROBADO"
        }
    ]
}

Response — Limit Exceeded 400

{
    "success": false,
    "message": "Límite máximo de 100 leads por request",
    "received": 150
}

Response — All Failed 400

{
    "success": false,
    "message": "0 de 3 leads actualizados exitosamente",
    "updated": 0,
    "failed": 3,
    "total": 3,
    "estado_nuevo": "APROBADO",
    "results": [
        {
            "lead_id": 999,
            "success": false,
            "message": "Lead no encontrado"
        },
        {
            "lead_id": 888,
            "success": false,
            "message": "No tienes permiso para este lead"
        },
        {
            "lead_id": 777,
            "success": false,
            "message": "Lead no encontrado"
        }
    ]
}

Use Cases

Casos de Uso

Bulk Update Lead Status (Async) 🚀

Actualización Masiva de Estado (Asíncrona) 🚀

Update the status of thousands of leads asynchronously. No limit on the number of leads. Responds immediately (202 Accepted) and processes in background.

Actualiza el estado de miles de leads de forma asíncrona. Sin límite en la cantidad de leads. Responde inmediatamente (202 Accepted) y procesa en segundo plano.

✅ Recommended for: Large updates (1000+ leads), multiple concurrent clients, no timeout concerns
✅ Recomendado para: Actualizaciones grandes (1000+ leads), múltiples clientes concurrentes, sin preocupaciones de timeout

Endpoint

Endpoint

POST /api/crm/leads/bulk-status-async

Allowed Roles

Roles Permitidos

Cliente (own leads only), Administrador

Cliente (solo sus propios leads), Administrador

Request Body

Cuerpo de la Petición

{
    "lead_ids": [1, 2, 3, 4, 5, ..., 5000],
    "estado": "contactado",
    "observaciones": "Procesamiento masivo de campaña SMS"
}

Rate Limiting

Limitación de Tasa

LimitValueDescription
Pending Jobs10Max concurrent jobs in queue per user
Jobs Per Day100Max jobs created per day per user
Job Size10,000Max leads per individual job
Daily Leads50,000Max total leads processed per day
Cooldown30sMin time between job submissions
LímiteValorDescripción
Jobs Pendientes10Máx jobs concurrentes en cola por usuario
Jobs Por Día100Máx jobs creados por día por usuario
Tamaño de Job10,000Máx leads por job individual
Leads Diarios50,000Máx leads totales procesados por día
Cooldown30sTiempo mín entre envío de jobs

Example cURL

Ejemplo cURL

curl -X POST "http://localhost/paqueteriacz/api/crm/leads/bulk-status-async" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \
  -d '{
    "lead_ids": [1, 2, 3, 4, 5, ..., 5000],
    "estado": "aprobado",
    "observaciones": "Procesamiento masivo"
  }'

Response — Job Queued 202 Accepted

{
    "success": true,
    "job_id": "bulk_6958aaf4d1477_1767418612",
    "status": "queued",
    "total_leads": 5000,
    "message": "Job encolado para procesamiento",
    "check_status_url": "/api/crm/jobs/bulk_6958aaf4d1477_1767418612"
}

Response — Job Queued with Warnings 202 Accepted

When some leads have validation errors but the job is still queued (pre-validation feedback):

Cuando algunos leads tienen errores de validación pero el job igualmente se encola (feedback de pre-validación):

{
    "success": true,
    "job_id": "bulk_6958b182d5773_1767420290",
    "status": "queued",
    "total_leads": 191,
    "message": "Job encolado. 188 leads pueden fallar.",
    "check_status_url": "/api/crm/jobs/bulk_6958b182d5773_1767420290",
    "valid_leads_count": 3,
    "error_rate": "98.43%",
    "validation_warnings": [
        {"lead_id": 10, "error": "No tienes permiso para este lead"},
        {"lead_id": 11, "error": "Lead no encontrado"},
        // ... más warnings
    ]
}
💡 Pre-Validation: The endpoint validates leads before queuing. If errors are found, they're shown in validation_warnings immediately, allowing you to decide whether to proceed or fix the issues.
💡 Pre-Validación: El endpoint valida leads antes de encolar. Si encuentra errores, se muestran en validation_warnings inmediatamente, permitiéndote decidir si proceder o corregir los problemas.

Response — Rate Limit Exceeded 429 Too Many

{
    "success": false,
    "error": "rate_limit_exceeded",
    "message": "Límite alcanzado: tienes 10 jobs pendientes (máximo 10)",
    "retry_after": 60
}

Advantages vs Synchronous

Ventajas vs Síncrono

SynchronousSíncronoAsynchronousAsíncrono
Max LeadsMáx Leads 100 100 10,000+ 10,000+
Response TimeTiempo Respuesta 200-500ms 200-500ms ~50ms ~50ms
Timeout RiskRiesgo Timeout Possible Posible Never Nunca
Concurrent ClientsClientes Concurrentes Limited Limitado Unlimited Ilimitados

Check Job Status

Consultar Estado de Job

Check the progress and status of an asynchronous bulk update job.

Consulta el progreso y estado de un job de actualización masiva asíncrona.

Endpoint

Endpoint

GET /api/crm/jobs/{job_id}

Allowed Roles

Roles Permitidos

Cliente (own jobs only), Administrador

Cliente (solo sus propios jobs), Administrador

URL Parameters

Parámetros de URL

ParameterParámetroDescriptionDescripción
job_id job_id Job identifier returned when creating the async job Identificador del job devuelto al crear el job asíncrono

Example cURL

Ejemplo cURL

curl -X GET "http://localhost/paqueteriacz/api/crm/jobs/bulk_6958aaf4d1477_1767418612" \
  -H "Authorization: Bearer <TOKEN>"

Response — Job Queued 200 OK

{
    "success": true,
    "job_id": "bulk_6958aaf4d1477_1767418612",
    "status": "queued",
    "total_leads": 5000,
    "processed_leads": 0,
    "successful_leads": 0,
    "failed_leads": 0,
    "estado": "APROBADO",
    "created_at": "2026-01-02 23:30:00",
    "started_at": null,
    "completed_at": null,
    "progress_percent": 0.0
}

Response — Job Processing 200 OK

{
    "success": true,
    "job_id": "bulk_6958aaf4d1477_1767418612",
    "status": "processing",
    "total_leads": 5000,
    "processed_leads": 2500,
    "successful_leads": 2498,
    "failed_leads": 2,
    "estado": "APROBADO",
    "created_at": "2026-01-02 23:30:00",
    "started_at": "2026-01-02 23:30:05",
    "completed_at": null,
    "progress_percent": 50.0
}

Response — Job Completed 200 OK

{
    "success": true,
    "job_id": "bulk_6958aaf4d1477_1767418612",
    "status": "completed",
    "total_leads": 5000,
    "processed_leads": 5000,
    "successful_leads": 4998,
    "failed_leads": 2,
    "estado": "APROBADO",
    "created_at": "2026-01-02 23:30:00",
    "started_at": "2026-01-02 23:30:05",
    "completed_at": "2026-01-02 23:30:35",
    "progress_percent": 100.0,
    "failed_details": [
        {"lead_id": 5, "error": "Sin permiso"},
        {"lead_id": 999, "error": "Lead no encontrado"}
    ]
}

Response — Job Completed (Many Failures) 200 OK

When there are more failures than successes, successful_details is shown instead:

Cuando hay más fallos que éxitos, se muestra successful_details en su lugar:

{
    "success": true,
    "job_id": "bulk_6958b3ea2e5ad_1767420906",
    "status": "completed",
    "total_leads": 191,
    "processed_leads": 191,
    "successful_leads": 3,
    "failed_leads": 188,
    "estado": "CANCELADO",
    "created_at": "2026-01-03 00:15:06",
    "started_at": "2026-01-03 00:15:06",
    "completed_at": "2026-01-03 00:15:08",
    "progress_percent": 100,
    "successful_details": [
        {"lead_id": 1, "estado_anterior": "EN_ESPERA", "estado_nuevo": "CANCELADO"},
        {"lead_id": 5, "estado_anterior": "EN_PROCESO", "estado_nuevo": "CANCELADO"},
        {"lead_id": 12, "estado_anterior": "APROBADO", "estado_nuevo": "CANCELADO"}
    ]
}
✅ Smart Response: The endpoint shows whichever array is smaller (successful_details or failed_details) to optimize response size and provide the most actionable information.
✅ Respuesta Inteligente: El endpoint muestra el array más pequeño (successful_details o failed_details) para optimizar el tamaño de respuesta y dar la información más útil.

Job Status Values

Valores de Estado del Job

StatusEstadoDescriptionDescripción
queued queued Waiting to be processed by worker Esperando ser procesado por el worker
processing processing Currently being processed Actualmente siendo procesado
completed completed Processing finished successfully Procesamiento terminado exitosamente
failed failed Job failed due to error Job falló debido a error
💡 Polling Recommendation: Poll this endpoint every 2-5 seconds to track progress. Avoid polling more frequently.
💡 Recomendación de Polling: Consulta este endpoint cada 2-5 segundos para rastrear el progreso. Evita consultar más frecuentemente.

List Leads

Listar Leads

Retrieve leads with filtering and pagination. Automatic role-based scoping applies.

Recupera leads con filtrado y paginación. Se aplica alcance automático basado en roles.

Endpoint

Endpoint

GET /api/crm/leads

Allowed Roles

Roles Permitidos

Cliente (own leads only), Administrador

Cliente (solo sus propios leads), Administrador

Query Parameters

Parámetros de Consulta

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger50Items per page (max 100)
estadostring-Filter by state
fecha_desdedate-From date (YYYY-MM-DD)
fecha_hastadate-To date (YYYY-MM-DD)
ParámetroTipoPor DefectoDescripción
pageinteger1Número de página
limitinteger50Items por página (máx 100)
estadostring-Filtrar por estado
fecha_desdedate-Desde fecha (YYYY-MM-DD)
fecha_hastadate-Hasta fecha (YYYY-MM-DD)

Example cURL

Ejemplo cURL

curl "http://localhost/paqueteriacz/api/crm/leads?page=1&limit=10&estado=APROBADO" \
  -H "Authorization: Bearer <TOKEN>"

View Lead Detail & Timeline

Ver Detalle de Lead y Cronología

Access full lead details or status change history.

Accede a los detalles completos del lead o historial de cambios de estado.

Endpoints

Endpoints

GET /api/crm/leads/{id}
GET /api/crm/leads/{id}/timeline

Allowed Roles

Roles Permitidos

Cliente (own lead only), Administrador

Cliente (solo su propio lead), Administrador

Example cURL

Ejemplo cURL

# View detail
curl "http://localhost/paqueteriacz/api/crm/leads/1" \
  -H "Authorization: Bearer <TOKEN>"

# View timeline
curl "http://localhost/paqueteriacz/api/crm/leads/1/timeline" \
  -H "Authorization: Bearer <TOKEN>"
# Ver detalle
curl "http://localhost/paqueteriacz/api/crm/leads/1" \
  -H "Authorization: Bearer <TOKEN>"

# Ver cronología
curl "http://localhost/paqueteriacz/api/crm/leads/1/timeline" \
  -H "Authorization: Bearer <TOKEN>"

System Metrics

Métricas del Sistema

Monitor CRM health and performance (admin-only).

Monitorea la salud y rendimiento del CRM (solo administrador).

Endpoint

Endpoint

GET /api/crm/metrics

Allowed Roles

Roles Permitidos

Administrador only

Solo Administrador

Example cURL

Ejemplo cURL

curl "http://localhost/paqueteriacz/api/crm/metrics" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

Webhooks (HMAC Signed)

Webhooks (Firmados con HMAC)

Receive real-time notifications via cryptographically signed webhooks.

Recibe notificaciones en tiempo real vía webhooks firmados criptográficamente.

Events

Eventos

Signature Verification (PHP)

Verificación de Firma (PHP)

$payload = file_get_contents("php://input");
$signature = $_SERVER['HTTP_X_SIGNATURE'];
$secret = 'your_shared_secret';

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (hash_equals($expected, $signature)) {
    $data = json_decode($payload, true);
    // Process webhook / Procesar webhook
} else {
    http_response_code(401);
    exit;
}

Configuration

Configuración

INSERT INTO crm_integrations (user_id, kind, webhook_url, secret, is_active)
VALUES (5, 'cliente', 'https://app.com/webhook', 'secret_123', 1);

Worker CLI

Worker CLI

Background worker for async processing with 3-second polling interval.

Worker en segundo plano para procesamiento asíncrono con intervalo de sondeo de 3 segundos.

1. General Worker (Webhooks & Retries)

1. Worker General (Webhooks y Reintentos)

# One-time execution (cron)
php cli/crm_worker.php --once

# Daemon mode (systemd)
php cli/crm_worker.php --loop
# Ejecución única (cron)
php cli/crm_worker.php --once

# Modo daemon (systemd)
php cli/crm_worker.php --loop

2. Bulk Update Worker 🚀

2. Worker de Actualización Masiva 🚀

Processes asynchronous bulk update jobs from POST /bulk-status-async.

Procesa jobs de actualización masiva asíncrona de POST /bulk-status-async.

# Start worker (runs continuously)
php cli/crm_bulk_worker.php

3. Maintenance & Cleanup 🧹

3. Mantenimiento y Limpieza 🧹

Removes old jobs and monitors stuck processes. Run daily via Cron/Task Scheduler.

Elimina jobs antiguos y monitorea procesos atascados. Ejecutar diariamente vía Cron/Task Scheduler.

# Run cleanup
php cli/crm_jobs_cleanup.php

Systemd Service

Servicio Systemd

[Unit]
Description=CRM Relay Worker
After=mariadb.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/xampp/htdocs/paqueteriacz
ExecStart=/usr/bin/php cli/crm_worker.php --loop
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl enable crm-worker
sudo systemctl start crm-worker
sudo journalctl -u crm-worker -f

Troubleshooting

Solución de Problemas

Monitoring Queries

Consultas de Monitoreo

-- Pending inbox count
SELECT COUNT(*) FROM crm_inbox WHERE status='pending';

-- Failed webhooks
SELECT id, event_type, attempts, last_error 
FROM crm_outbox 
WHERE status='failed' 
LIMIT 10;

-- Recent leads
SELECT id, proveedor_lead_id, estado_actual, created_at 
FROM crm_leads 
ORDER BY created_at DESC 
LIMIT 20;
-- Conteo de inbox pendientes
SELECT COUNT(*) FROM crm_inbox WHERE status='pending';

-- Webhooks fallidos
SELECT id, event_type, attempts, last_error 
FROM crm_outbox 
WHERE status='failed' 
LIMIT 10;

-- Leads recientes
SELECT id, proveedor_lead_id, estado_actual, created_at 
FROM crm_leads 
ORDER BY created_at DESC 
LIMIT 20;

HTTP Status Codes

Códigos de Estado HTTP

CodeMeaningWhen
200OKSuccessful query, update, or idempotent retry
202AcceptedLead queued for async processing
400Bad RequestValidation error, invalid transition
401UnauthorizedMissing/invalid JWT token
403ForbiddenInsufficient permissions or ownership
404Not FoundLead ID doesn't exist
CódigoSignificadoCuándo
200OKConsulta exitosa, actualización o reintento idempotente
202AceptadoLead encolado para procesamiento asíncrono
400Solicitud IncorrectaError de validación, transición inválida
401No AutorizadoToken JWT faltante/inválido
403ProhibidoPermisos insuficientes o falta de propiedad
404No EncontradoID de lead no existe