Guías
Conectar un CRM personalizado a Azter
Conecta tu CRM, formulario o landing page para que cada lead llegue a Azter automáticamente: se crea el contacto, la oportunidad comercial y —si hay consentimiento— se envía el primer mensaje por WhatsApp.
Cómo funciona
Azter expone un endpoint HTTP autenticado con firma HMAC. Tu sistema envía un POST por cada lead nuevo; Azter verifica la firma, registra el evento y ejecuta la activación. No necesitas SDK: cualquier lenguaje con HTTP y HMAC-SHA256 sirve.
- Cada conector pertenece a tu empresa (workspace) y tiene su propio secret.
- Las peticiones se firman con HMAC-SHA256 y expiran a los 5 minutos (protección contra replay).
- Los reenvíos del mismo lead son idempotentes: no se duplican contactos ni mensajes.
- El consentimiento de WhatsApp viaja en el payload y se audita en un registro inmutable.
1. Crear el conector
En Azter, un owner o admin de tu empresa va a Integraciones y crea un conector. Elige un nombre visible (ej. "CRM Properly") y un identificador de sistema sin espacios (ej. properly_crm). Azter genera el secret en el servidor y lo muestra una sola vez: guárdalo en un gestor de secretos, nunca en el código. Nadie puede volver a verlo después — solo reemplazarlo rotándolo.
La pantalla del conector te entrega dos datos que tu desarrollador necesita: el endpoint (POST /functions/v1/lead-intake) y el ID del conector (un UUID). Si el secret se compromete, un owner/admin puede rotarlo desde la misma pantalla; el anterior deja de funcionar de inmediato y el nuevo se muestra una sola vez.
2. Enviar un lead
Cada lead nuevo se envía como un POST con tres headers de autenticación (el endpoint exacto aparece en la pantalla del conector en Integraciones):
1curl -X POST <endpoint-de-integraciones> \2 -H "Content-Type: application/json" \3 -H "X-Azter-Connector-Id: <connector_id>" \4 -H "X-Azter-Timestamp: <unix_ms>" \5 -H "X-Azter-Signature: <hmac_hex>" \6 -d @lead.json- X-Azter-Connector-Id: el UUID del conector.
- X-Azter-Timestamp: milisegundos Unix actuales (máximo 5 minutos de antigüedad).
- X-Azter-Signature: HMAC-SHA256 del secret sobre timestamp + "." + cuerpo crudo.
3. Firmar la petición
La firma se calcula sobre el cuerpo crudo (raw body) tal como se transmite — no sobre el objeto parseado. Primero concatena timestamp + "." + body, firma con tu secret y envía el resultado en hexadecimal:
1import { createHmac } from "node:crypto";23const body = JSON.stringify(payload);4const timestamp = Date.now().toString();56const signature = createHmac("sha256", CONNECTOR_SECRET)7 .update(timestamp + "." + body)8 .digest("hex");910await fetch(ENDPOINT, {11 method: "POST",12 headers: {13 "Content-Type": "application/json",14 "X-Azter-Connector-Id": CONNECTOR_ID,15 "X-Azter-Timestamp": timestamp,16 "X-Azter-Signature": signature,17 },18 body,19});Importante
Payload
1{2 "event": "lead.created",3 "source_lead_id": "crm-lead-8841",4 "contact": {5 "name": "María González",6 "phone_e164": "+56912345678",7 "email": "maria@ejemplo.cl"8 },9 "context": {10 "catalog_item_id": "torre-norte-2d",11 "source": "meta_ads",12 "campaign_id": "1202••••",13 "landing_page": "https://tusitio.cl/torre-norte"14 },15 "qualification": {16 "monthly_income": 280000017 },18 "whatsapp_consent": {19 "granted": true,20 "timestamp": "2026-08-30T14:03:00Z",21 "source": "crm_form",22 "purpose": "lead_followup"23 },24 "metadata": { "notas": "Consultó por 2 dormitorios" }25}Campos
- event: hoy solo se acepta "lead.created".
- source_lead_id (obligatorio): identificador único del lead en tu sistema. Azter lo usa para idempotencia.
- contact.phone_e164 (obligatorio): teléfono en formato E.164 con +.
- contact.name / contact.email (opcionales): se usan para identidad y enriquecimiento.
- context (opcional): atribución — de dónde vino el lead (campaña, anuncio, landing, producto).
- qualification (opcional): calificación ya conocida por el CRM. Solo campos definidos por el vertical del workspace (inmobiliario: monthly_income en CLP). Currency/number exigen number finito ≥ 0 — Azter NO infiere montos desde texto ("2.800.000" o rangos se rechazan con razón explícita). Los campos válidos se registran en la oportunidad con evidencia del conector; desconocidos/inválidos se rechazan con reason, nunca en silencio.
- whatsapp_consent (opcional pero recomendado): evidencia del consentimiento para contactar por WhatsApp.
- metadata (opcional): texto libre para tu propio trazado (no se trata como calificación confiable).
Respuesta
1{2 "accepted": true,3 "duplicate": false,4 "lead_event_id": "••••",5 "contact_id": "••••",6 "opportunity_id": "••••",7 "eligible_for_whatsapp": true,8 "outbound": { "status": "sent", "reason": null }9}outbound.status indica qué pasó con el primer mensaje: sent (enviado), queued, blocked (sin consentimiento o con opt-out previo) o failed (error del proveedor). El lead queda registrado igual en todos los casos.
Idempotencia y reintentos
El par (connector_id, source_lead_id) es único. Si reenvías el mismo lead — por timeouts o reintentos — Azter responde 200 con duplicate: true y el estado previo, sin crear nada nuevo ni reenviar mensajes. Puedes reintentar con seguridad ante cualquier error de red.
Consentimiento
Azter solo envía WhatsApp si whatsapp_consent.granted es true con su timestamp. El consentimiento se persiste en un registro auditable junto al origen que lo declaró. Si el contacto tiene una revocación previa (opt-out) en Azter, el envío se bloquea aunque el payload traiga consentimiento.