Endpoints CRM
Conecta WAzion con tu CRM o ERP externo para que la IA y el panel lateral accedan a datos de clientes, pedidos y productos de tu sistema.
¿Qué son los Endpoints CRM?
Los Endpoints CRM permiten que WAzion consulte información de tu sistema externo (CRM, ERP, base de datos propia). A diferencia de las Funciones IA (que la IA decide cuándo llamar), estos endpoints se llaman automáticamente cuando el agente abre una conversación o busca información.
Para el Panel Lateral
Muestra datos del cliente junto a la conversación (pedidos, historial, información de contacto).
Para la IA
Proporciona contexto inicial sobre el cliente para que la IA responda con información relevante.
1 sidePanel_CustomerInfo
Proporciona información del cliente que se muestra en el panel lateral de la extensión cuando el agente abre una conversación.
Parámetros enviados
| phone | Teléfono del cliente (E.164) |
| token | Token de autenticación |
| relatedphones | Teléfonos relacionados (array) |
Respuesta esperada
{
"found": true,
"customers": [
{
"name": "Juan García",
"email": "juan@email.com",
"phone": "+34612345678",
"shopUrl": "https://tucrm.com/c/123",
"ordersCount": 5,
"totalSpent": 450.00,
"totalRefunded": 0,
"state": "VIP - Activo",
"orders": [...],
"abandonedCarts": [...]
}
]
}
Nota: Puedes usar “customer“ (objeto) o “customers“ (array) para soportar múltiples clientes. SIEMPRE devuelve HTTP 200, incluso si no encuentras cliente (usa “found“: false).
📦 Ver estructura completa de respuesta (orders, items, tracking, abandonedCarts)
Estructura JSON completa con todos los campos soportados:
{
"found": true,
"customers": [
{
"// Datos básicos del cliente"
"name": "Juan García López",
"email": "juan@email.com",
"phone": "+34612345678",
"shopUrl": "https://tu-crm.com/clientes/123",
"ordersCount": 15,
"totalSpent": 1250.50,
"totalRefunded": 50.00,
"totalDiscounts": 25.00,
"state": "Cliente VIP",
"// Array de pedidos"
"orders": [
{
"name": "#ORD-2025-001",
"date": "2025-01-10T14:30:00Z",
"amount": 129.99,
"netAmount": 104.99,
"totalRefunded": 25.00,
"totalDiscounts": 10.00,
"currency": "EUR",
"cancelled": false,
"shopUrl": "https://tu-crm.com/pedidos/1234",
"note": "Entregar por la tarde",
"// Items del pedido"
"items": [
{
"title": "Camiseta Premium Azul - Talla L",
"quantity": 2,
"currentQuantity": 2,
"amount": 59.98,
"originalAmount": 59.98,
"discountedAmount": 59.98,
"discount": 0,
"refundedQuantity": 0,
"refundedAmount": 0,
"status": "active" // active | partially_refunded | fully_refunded
}
],
"// Tracking de envíos"
"tracking": [
{
"number": "ES123456789012",
"company": "SEUR",
"url": "https://www.seur.com/tracking/...",
"displayStatus": "Entregado"
}
]
}
],
"// Carritos abandonados"
"abandonedCarts": [
{
"date": "2025-01-14T18:45:00Z",
"url": "https://tu-tienda.com/cart/recover/abc123",
"items": [
{
"title": "Zapatillas Running Pro",
"quantity": 1,
"amount": 129.99
}
]
}
]
}
]
}
Campos del cliente:
| Campo | Tipo | Requerido |
|---|---|---|
| name | string | Sí |
| string | Sí | |
| phone | string | Sí |
| shopUrl | string | No |
| ordersCount | number | Sí |
| totalSpent | number | Sí |
| totalRefunded | number | No |
| totalDiscounts | number | No |
| state | string | Sí |
| orders | array | No |
| abandonedCarts | array | No |
Campos del pedido (order):
| Campo | Tipo | Descripción |
|---|---|---|
| name | string | ID/Número del pedido |
| date | string | Fecha ISO 8601 |
| amount | number | Total del pedido |
| netAmount | number | Importe neto (tras reembolsos) |
| currency | string | Código de moneda (EUR, USD...) |
| cancelled | boolean | true si está cancelado |
| shopUrl | string | URL al pedido en tu sistema |
| note | string | Nota del pedido |
| items | array | Productos del pedido |
| tracking | array | Envíos/tracking |
Campos del item:
| Campo | Tipo | Descripción |
|---|---|---|
| title | string | Nombre del producto |
| quantity | number | Cantidad pedida |
| currentQuantity | number | Cantidad actual (tras reembolsos) |
| amount | number | Precio total del item |
| refundedQuantity | number | Unidades reembolsadas |
| refundedAmount | number | Importe reembolsado |
| status | string | active | partially_refunded | fully_refunded |
Campos del tracking:
| Campo | Tipo | Descripción |
|---|---|---|
| number | string | Número de seguimiento |
| company | string | Empresa de envío |
| url | string | URL de seguimiento |
| displayStatus | string | Estado legible (Entregado, En tránsito...) |
Labels de traducción (UI)
Para que la extensión muestre los textos en el idioma correcto, incluye el objeto “labels“ con las traducciones:
{
"found": true,
"customer": { ... },
"labels": {
"label_languages": "es",
"customer_info": "Información del Cliente",
"name": "Nombre",
"email": "Email",
...
}
}
Ver tabla completa de labels disponibles
| Key | Default (ES) | Descripción |
|---|---|---|
| label_languages | "es" | Idioma de las etiquetas. Si difiere del idioma de la tienda, WAzion las traduce automáticamente |
| customer_info | "Información del Cliente" | Título sección cliente |
| name | "Nombre" | Etiqueta nombre |
| "Email" | Etiqueta email | |
| phone | "Teléfono" | Etiqueta teléfono |
| orders_count | "Pedidos" | Contador de pedidos |
| total_spent | "Total gastado" | Total gastado |
| total_refunded | "Total reembolsado" | Reembolsos |
| discounts | "Descuentos" | Descuentos |
| customer_state | "Estado" | Estado del cliente |
| recent_orders | "Pedidos recientes" | Título pedidos |
| order | "Pedido" | Pedido individual |
| orders | "Pedidos" | Pedidos (plural) |
| order_number | "Nº de pedido" | Número de pedido |
| date | "Fecha" | Fecha |
| amount | "Importe" | Importe |
| net_amount | "Importe neto" | Importe neto |
| subtotal | "Subtotal" | Subtotal |
| discount | "Descuento" | Descuento individual |
| refund | "Reembolso" | Reembolso |
| refunded | "Reembolsado" | Badge reembolsado |
| cancelled | "Cancelado" | Badge cancelado |
| cancel_reason | "Motivo cancelación" | Motivo de cancelación |
| items | "Artículos" | Productos/Artículos |
| item_status | "Estado artículo" | Estado del artículo |
| quantity | "Cantidad" | Cantidad |
| original_quantity | "Cantidad original" | Cantidad original |
| current_quantity | "Cantidad actual" | Cantidad actual |
| sku | "SKU" | SKU |
| shipments | "Envíos" | Envíos |
| shipping | "Envío" | Envío individual |
| tracking_number | "Nº seguimiento" | Número de seguimiento |
| no_shipping_info | "Sin información de envío" | Sin envío |
| order_note | "Nota del pedido" | Notas del pedido |
| fully_refunded | "Reembolsado completamente" | Ítem 100% reembolsado |
| partially_refunded | "Reembolsado parcialmente" | Ítem parcialmente reembolsado |
| active | "Activo" | Estado activo |
| abandoned_carts | "Carrito/s abandonado/s" | Carritos abandonados |
| copy_link | "Copiar enlace" | Botón copiar |
| view_customer | "Ver perfil del cliente" | Botón ver cliente |
| view_profile | "Ver perfil" | Botón ver perfil |
| remove_assignment | "Quitar asignación" | Botón desvincular |
| not_found | "Cliente no encontrado" | Mensaje no encontrado |
| no_orders | "Sin pedidos" | Sin pedidos |
| error | "Error" | Prefijo de error |
| Estados del cliente | ||
| state_no_orders | "Sin pedidos" | Estado: sin pedidos |
| state_conflictive | "Conflictivo" | Estado: conflictivo |
| state_processing | "Procesando" | Estado: procesando |
| state_new_orders | "Pedidos nuevos" | Estado: pedidos nuevos |
| state_recent_orders | "Pedidos recientes" | Estado: pedidos recientes |
| state_old_orders | "Pedidos antiguos" | Estado: pedidos antiguos |
Traducción automática: Si envías labels en un idioma (ej: inglés con label_languages: “en“) y la tienda está configurada en otro (ej: español), WAzion traducirá automáticamente todos los labels. Esto te permite mantener tu CRM en un solo idioma.
2 ai_CustomerInitialInfo
Proporciona contexto inicial sobre el cliente a la IA. Este texto se incluye en el prompt de la IA para que pueda responder con información relevante del cliente.
Parámetros enviados
| phone | Teléfono del cliente (E.164) |
| token | Token de autenticación |
| relatedphones | Teléfonos relacionados (array) |
| order | Número de pedido mencionado (opcional) |
| Email del cliente (opcional) | |
| test | “true“ si es prueba |
Respuesta esperada
{
"found": true,
"info": "Cliente: Juan García.
VIP: Sí. Total pedidos: 5.
Último pedido: #12345 (15/01/2024)
Estado: Entregado.
Productos frecuentes: Zapatos, Camisetas.
ALERTA: Cliente alérgico al gluten."
}
Importante: El campo “info“ es texto libre que la IA leerá como contexto. Incluye historial de compras, preferencias, alertas importantes (alergias, problemas previos), estado del cliente, método de pago/envío preferido, etc.
3 sidePanel_CustomerFindToJoin
Permite buscar clientes en tu sistema para vincularlos a una conversación de WhatsApp. Útil cuando el cliente escribe desde un número diferente al registrado.
Parámetros enviados
| query | Texto de búsqueda |
| token | Token de autenticación |
| phone | Teléfono actual de la conversación |
| relatedphones | Teléfonos ya relacionados (array, para excluirlos) |
Respuesta esperada
{
"customers": [
{
"id": "cust_123",
"name": "Juan García",
"email": "juan@email.com",
"phone": "+34612345678"
},
{
"id": "cust_456",
"name": "Juan Martínez",
"email": "juanm@email.com",
"phone": "+34687654321"
}
]
}
Nota: Puedes usar “customers“ o “results“ como nombre del array. El campo “phone“ de cada cliente permite a WAzion vincular automáticamente la conversación.
4 search_Products
Permite buscar productos en tu catálogo externo. Los resultados se muestran en el panel lateral y el agente puede compartirlos con el cliente. La IA también puede buscar productos para responder preguntas.
Nota para CRM Custom: WAzion actúa como proxy transparente para este endpoint. La respuesta de tu CRM se devuelve directamente a la extensión sin modificar. Debes implementar la estructura completa documentada si quieres aprovechar todas las funcionalidades. Los campos enriquecidos (target_locale, title_copy, raw, etc.) solo se generan automáticamente para tiendas Shopify.
Parámetros enviados
| Parámetro | Tipo | Descripción |
|---|---|---|
| q | string | Texto de búsqueda (mínimo 2 caracteres) |
| token | string | Token de autenticación de la tienda |
| phone | string | Teléfono del cliente (E.164) - para URLs localizadas por país |
| format | string | “ai“ cuando la IA busca productos (cambia estructura de respuesta) |
| target_locale | string | Idioma detectado del cliente basado en su teléfono (ej: “es“, “de“, “fr“) |
| test | boolean | “true“ si es prueba de conexión |
Nuevo: target_locale - WAzion detecta automáticamente el idioma del cliente basándose en el prefijo de su teléfono. Por ejemplo, +34... → “es“, +49... → “de“. Usa este parámetro para devolver productos en el idioma correcto.
Respuesta formato NORMAL (panel lateral)
Cuando el agente busca productos desde el panel. Incluye campos para copiar/compartir.
{
"http_status": 200,
"count": 1,
"products": [
{
"title": "Camiseta Premium",
"title_copy": "Premium T-Shirt",
"handle": "camiseta-premium",
"description": "Descripción truncada a 500 chars...",
"sku": "CAM-001",
"image": "https://proxy/imagen.jpg",
"url": "https://tutienda.es/products/camiseta-premium",
"variants": [
{
"id": "12345678",
"title": "M / Rojo",
"title_copy": "M / Red",
"has_custom_title": true,
"sku": "CAM-001-M-RED",
"image": "https://proxy/variante.jpg",
"url": "https://tutienda.es/products/camiseta-premium?variant=12345678"
}
]
}
],
"target_locale": "en",
"raw": { ... }
}
Respuesta formato AI (cuando format=“ai“)
Cuando la IA busca productos. Estructura simplificada sin campos de copia, descripción completa.
{
"count": 1,
"products": [
{
"title": "Premium T-Shirt",
"handle": "camiseta-premium",
"description": "Descripción COMPLETA sin truncar para contexto IA...",
"sku": "CAM-001",
"url": "https://tutienda.es/products/camiseta-premium",
"variants": [
{
"id": "12345678",
"title": "M / Red",
"sku": "CAM-001-M-RED",
"url": "https://tutienda.es/products/camiseta-premium?variant=12345678"
}
]
}
],
"locale": "en"
}
Ver todos los campos del producto
| Campo | Normal | AI | Descripción |
|---|---|---|---|
| title | Original | Traducido | Título del producto |
| title_copy | Traducido | - | Título para copiar (idioma del cliente) |
| handle | ✓ | ✓ | Slug del producto |
| description | 500 chars | Completa | Descripción (HTML limpiado) |
| sku | ✓ | ✓ | SKU de la primera variante |
| image | ✓ | - | URL de imagen (puede ser proxied) |
| url | ✓ | ✓ | URL localizada del producto |
| variants | ✓ | ✓ | Array de variantes |
Ver campos de cada variante
| Campo | Normal | AI | Descripción |
|---|---|---|---|
| id | ✓ | ✓ | ID de la variante |
| title | Original | Traducido | Título de variante (ej: “M / Rojo“) |
| title_copy | Traducido | - | Título para copiar (idioma del cliente) |
| has_custom_title | ✓ | - | true si tiene título personalizado (no “Default Title“) |
| sku | ✓ | ✓ | SKU de la variante |
| image | ✓ | - | Imagen específica de variante (o del producto si no tiene) |
| url | ✓ | ✓ | URL con ?variant=ID |
Ver campos de la respuesta raíz
| Campo | Normal | AI | Descripción |
|---|---|---|---|
| http_status | ✓ | - | Código HTTP de la respuesta |
| count | ✓ | ✓ | Número de productos encontrados |
| products | ✓ | ✓ | Array de productos |
| target_locale | ✓ | - | Locale usado para traducciones |
| locale | - | ✓ | Locale usado (solo formato AI) |
| raw | ✓ | - | Respuesta raw de la fuente (debug) |
🌍 URLs localizadas por país
El parámetro phone contiene el teléfono del cliente (E.164). Úsalo para detectar su país y devolver URLs adaptadas:
- Dominios específicos por país (tutienda.es, tutienda.de, tutienda.fr)
- Rutas con prefijo de idioma (/es/, /de/, /fr/)
- Parámetros de locale (?locale=es_ES)
- Markets de Shopify específicos
Ejemplo: Si el teléfono empieza por +34 (España), devolver URLs con dominio .es o /es/.
5 globalSearch
Búsqueda global de clientes para el buscador flotante de la extensión. Permite buscar por nombre, email, teléfono o número de pedido.
Parámetros enviados
| Parámetro | Tipo | Descripción |
|---|---|---|
| query | string | Texto de búsqueda (mínimo 2 caracteres) |
| token | string | Token de autenticación de la tienda |
Respuesta esperada
{
"found": true,
"customers": [
{
"id": "cust_123",
"name": "Juan García López",
"email": "juan.garcia@email.com",
"phone": "+34612345678",
"customerUrl": "https://tucrm.com/clientes/123",
"orders": [
{
"number": "#ORD-1234",
"url": "https://tucrm.com/pedidos/1234"
},
{
"number": "#ORD-1233",
"url": "https://tucrm.com/pedidos/1233"
}
]
}
]
}
Campos de cada cliente
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| id | string | Sí | ID único del cliente en tu sistema |
| name | string | Sí | Nombre completo del cliente |
| string | Sí | Email del cliente | |
| phone | string | Sí | Teléfono del cliente (E.164 preferido, ej: +34612345678) |
| customerUrl | string | No | URL para ver el cliente en tu CRM (se muestra como enlace clickeable) |
| orders | array | No | Array con los últimos pedidos (máximo 3) |
Campos de cada pedido (orders[])
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| number | string | Sí | Número de pedido (ej: “#ORD-1234“) |
| url | string | No | URL para ver el pedido en tu sistema |
Notas importantes
- • El campo
phonees obligatorio para que el agente pueda abrir la conversación con ese cliente. - • Máximo 15 resultados serán mostrados al usuario (limitado automáticamente).
- • Los duplicados por teléfono se eliminan automáticamente.
- • Si
customerUrlestá presente, el nombre del cliente será un enlace clickeable. - • Los pedidos se muestran como enlaces individuales debajo del cliente.
Especificaciones Técnicas
Timeouts
| globalSearch | 5s |
| Otros endpoints | 10s |
| Connect timeout | 5s |
| Reintentos | No |
Métodos HTTP
| Configurable | GET / POST |
| Body (POST) | JSON / Form |
| Parámetros (GET) | Query string |
Requisitos
- HTTPS obligatorio
- Respuesta JSON válida
- HTTP 200 siempre (usar found:false si no hay datos)
Diferencia con Funciones IA
Los Endpoints CRM NO reintentan automáticamente si fallan. Se llaman en tiempo real mientras el agente trabaja, así que deben responder rápido. Si falla, la información simplemente no aparece.
Tipos de Autenticación
Ejemplo URL (GET + query auth)
// WAzion llamará:
https://tu-api.com/customer
?phone=+34612345678
&token=tu-token-secreto
&relatedphones=["+34698765432"]
&test=false
Ejemplos de Implementación
<?php
// Endpoint: /api/customer-info
header('Content-Type: application/json');
// Obtener parámetros (soporta GET y POST)
$input = json_decode(file_get_contents('php://input'), true) ?? $_GET;
$phone = $input['phone'] ?? '';
$token = $input['token'] ?? '';
$relatedPhones = $input['relatedphones'] ?? [];
$order = $input['order'] ?? '';
$isTest = ($input['test'] ?? '') === 'true';
// Verificar token
if ($token !== 'tu-token-secreto') {
echo json_encode(['found' => false, 'error' => 'No autorizado']);
exit;
}
// Si es test, devolver datos de ejemplo
if ($isTest) {
echo json_encode([
'found' => true,
'customers' => [[
'name' => 'Cliente de Prueba',
'email' => 'test@example.com',
'phone' => '+34612345678',
'shopUrl' => 'https://tucrm.com/cliente/123',
'ordersCount' => 3,
'totalSpent' => 150.00,
'state' => 'Activo',
'orders' => []
]]
]);
exit;
}
// Buscar por teléfono principal + relacionados
$allPhones = array_merge([$phone], $relatedPhones);
$customers = buscarClientesPorTelefonos($allPhones);
echo json_encode([
'found' => !empty($customers),
'customers' => $customers
]);
const express = require('express');
const app = express();
app.use(express.json());
const SECRET_TOKEN = 'tu-token-secreto';
app.all('/api/customer-info', async (req, res) => {
// Soporta GET y POST
const params = { ...req.query, ...req.body };
const { phone, token, relatedphones = [], order, test } = params;
// Verificar token
if (token !== SECRET_TOKEN) {
return res.json({ found: false, error: 'No autorizado' });
}
// Datos de test
if (test === 'true') {
return res.json({
found: true,
customers: [{
name: 'Cliente de Prueba',
email: 'test@example.com',
phone: '+34612345678',
shopUrl: 'https://tucrm.com/cliente/123',
ordersCount: 3,
totalSpent: 150.00,
state: 'Activo',
orders: []
}]
});
}
// Buscar clientes
const allPhones = [phone, ...relatedphones];
const customers = await buscarClientesPorTelefonos(allPhones);
res.json({ found: customers.length > 0, customers });
});
app.listen(3000);
from flask import Flask, request, jsonify
app = Flask(__name__)
SECRET_TOKEN = 'tu-token-secreto'
@app.route('/api/customer-info', methods=['GET', 'POST'])
def customer_info():
# Soporta GET y POST
params = {**request.args, **request.get_json(silent=True) or {}}
phone = params.get('phone', '')
token = params.get('token', '')
related_phones = params.get('relatedphones', [])
is_test = params.get('test') == 'true'
# Verificar token
if token != SECRET_TOKEN:
return jsonify({'found': False, 'error': 'No autorizado'})
# Datos de test
if is_test:
return jsonify({
'found': True,
'customers': [{
'name': 'Cliente de Prueba',
'email': 'test@example.com',
'phone': '+34612345678',
'shopUrl': 'https://tucrm.com/cliente/123',
'ordersCount': 3,
'totalSpent': 150.00,
'state': 'Activo',
'orders': []
}]
})
# Buscar clientes
all_phones = [phone] + related_phones
customers = buscar_clientes_por_telefonos(all_phones)
return jsonify({'found': len(customers) > 0, 'customers': customers})
Historial de cambios
sidePanel_CustomerInfo ahora traduce automáticamente todos los labels si label_languages difiere del idioma de la tienda. Puedes mantener tu CRM en un solo idioma (ej: inglés) y WAzion se encarga de las traducciones.
WAzion ahora envía el idioma detectado del cliente (basado en el prefijo de su teléfono) como parámetro target_locale. Útil para devolver productos en el idioma correcto del cliente.