Volver al sitio
Syncro

Webhooks

Suscríbete a eventos y recibe notificaciones en tiempo real en tu URL, con cada entrega firmada mediante HMAC.

Base URLhttps://app.syncro.chat/api/v1AuthX-API-Key: crm_SUA_CHAVE_AQUI

Listar suscripciones

GET/webhooks
Permiso: webhooks:read

Lista las suscripciones de webhook de la cuenta.

Solicitud
curl "https://app.syncro.chat/api/v1/webhooks" \
  -H "X-API-Key: crm_SUA_CHAVE_AQUI"
Respuesta
{
  "success": true,
  "data": [
    {
      "id": 1,
      "target_url": "https://seu-sistema.com/webhooks/syncro",
      "events": [
        "lead.created",
        "lead.updated"
      ],
      "source": "api",
      "is_active": true,
      "failure_count": 0,
      "last_success_at": "2026-06-30T10:05:00Z",
      "last_failure_at": null,
      "created_at": "2026-06-15T14:30:00Z"
    }
  ],
  "supported_events": [
    "lead.created",
    "lead.updated",
    "lead.stage_changed",
    "..."
  ]
}

Crear suscripción

POST/webhooks
Permiso: webhooks:write

Crea una suscripción apuntando a tu URL y elige qué eventos recibir.

Parámetros del body

target_urlstring (URL)obligatorio
URL que recibirá los POST
eventsarray(string)obligatorio
Eventos a suscribir (ver lista)
sourcestringopcional
api (predeterminado) o n8n
secretstringopcional
Secreto del HMAC. Si se omite, Syncro **genera uno** y lo devuelve
i

Guarda el secret: lo usarás para validar la firma de cada entrega.

Solicitud
curl -X POST "https://app.syncro.chat/api/v1/webhooks" \
  -H "X-API-Key: crm_SUA_CHAVE_AQUI" \
  -H "Content-Type: application/json" \
  -d '{
    "target_url": "https://seu-sistema.com/webhooks/syncro",
    "events": [
      "lead.created",
      "lead.won",
      "task.completed"
    ]
  }'
Respuesta
{
  "success": true,
  "id": 1,
  "secret": "f3a9c2...e1",
  "events": [
    "lead.created",
    "lead.won",
    "task.completed"
  ]
}

Detalle de una suscripción

GET/webhooks/1
Permiso: webhooks:read

Devuelve los datos de una suscripción específica.

Solicitud
curl "https://app.syncro.chat/api/v1/webhooks/1" \
  -H "X-API-Key: crm_SUA_CHAVE_AQUI"
Respuesta
{
  "success": true,
  "id": 1,
  "target_url": "https://seu-sistema.com/webhooks/syncro",
  "events": [
    "lead.created",
    "lead.updated"
  ],
  "source": "api",
  "is_active": true,
  "failure_count": 0,
  "last_success_at": "2026-06-30T10:05:00Z",
  "last_failure_at": null,
  "last_failure_reason": null
}

Actualizar suscripción

PUT/webhooks/1
Permiso: webhooks:write

Actualiza la URL, los eventos o activa/desactiva. Reactivar (is_active: true) reinicia el contador de fallos.

Parámetros (body, todos opcionales)

target_urlstring (URL)opcional
Nueva URL
eventsarray(string)opcional
Nueva lista de eventos
is_activebooleanopcional
Activa/desactiva
Solicitud
curl -X PUT "https://app.syncro.chat/api/v1/webhooks/1" \
  -H "X-API-Key: crm_SUA_CHAVE_AQUI" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      "lead.created"
    ],
    "is_active": true
  }'
Respuesta
{
  "success": true,
  "id": 1,
  "events": [
    "lead.created"
  ],
  "is_active": true
}

Eliminar suscripción

DELETE/webhooks/1
Permiso: webhooks:write

Elimina una suscripción de webhook.

Solicitud
curl -X DELETE "https://app.syncro.chat/api/v1/webhooks/1" \
  -H "X-API-Key: crm_SUA_CHAVE_AQUI"
Respuesta
{
  "success": true
}

Cómo funciona la entrega

Cuando ocurre un evento suscrito, Syncro hace un POST (JSON) a tu target_url.

Envelope

Cada evento llega en este formato:

{
  "event": "lead.created",
  "tenant_id": 1,
  "emitted_at": "2026-06-30T10:00:00Z",
  "data": {
    "...": "payload específico do evento"
  }
}

Headers de la entrega

Header Valor
Content-Type application/json
User-Agent Syncro-CRM-Webhook/1.0
X-Syncro-Event nombre del evento (ej.: lead.created)
X-Syncro-Delivery ID único de la entrega
X-Syncro-Signature sha256=<hmac> — firma HMAC del cuerpo

Validando la firma (HMAC)

La firma es el HMAC-SHA256 del cuerpo bruto de la solicitud, usando el secret de la suscripción como clave. El header viene como sha256=<hash_hexadecimal>.

Calcula el HMAC sobre el cuerpo bruto recibido (no vuelvas a serializar el JSON) y compara con el valor tras sha256=.

Node.js (Express)

const crypto = require('crypto');

// use o corpo BRUTO: app.use(express.raw({ type: 'application/json' }))
function verify(req, secret) {
  const header = req.get('X-Syncro-Signature') || '';
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(req.body) // Buffer com o corpo bruto
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

PHP

$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
$ok = hash_equals($expected, $_SERVER['HTTP_X_SYNCRO_SIGNATURE'] ?? '');

Responde con 2xx para confirmar la recepción. Cualquier otro estado se trata como un fallo.

Reentregas y retry

  • Syncro intenta entregar hasta 4 veces, con espera creciente: 10s, 1min, 5min, 15min.
  • Las respuestas 5xx, 408 y 429 se reenvían. Las respuestas 4xx (excepto 408/429) no se reenvían (error del receptor).
  • Tras 10 fallos consecutivos, la suscripción se desactiva automáticamente (reactívala con PUT /webhooks/{id} e is_active: true).
  • Haz tu endpoint idempotente (puede recibir la misma entrega más de una vez); usa el X-Syncro-Delivery para deduplicar.

Eventos disponibles

Evento Cuándo se dispara
lead.created Lead creado
lead.updated Lead actualizado
lead.stage_changed Lead cambió de etapa
lead.won Lead marcado como ganado
lead.lost Lead marcado como perdido
lead.deleted Lead eliminado
lead.assignment_changed Responsable del lead cambió
lead.merged Leads fusionados
lead.tags_changed Tags del lead cambiaron
sale.created Venta registrada
note.added Nota añadida a un lead
nps.answered Encuesta NPS respondida
task.created Tarea creada
task.updated Tarea actualizada
task.completed Tarea completada
conversation.message_received Reservado (aún no emitido)

Ejemplos de payload

Ejemplos del campo data:

lead.created / lead.updated / lead.deleted

{
  "id": 123,
  "name": "João Silva",
  "email": "[email protected]",
  "phone": "+5511999887766",
  "company": "ACME",
  "value": 5000.0,
  "source": "site",
  "status": "open",
  "pipeline_id": 1,
  "pipeline_name": "Vendas",
  "stage_id": 5,
  "stage_name": "Proposta",
  "assigned_to": 12,
  "owner": { "id": 12, "name": "Ana", "email": "[email protected]" },
  "tags": ["vip"],
  "utm_source": "google",
  "utm_medium": "cpc",
  "utm_campaign": "verao_2026",
  "utm_term": null,
  "utm_content": null,
  "fbclid": null,
  "gclid": null,
  "custom_fields": { "tamanho_empresa": "100+" },
  "created_at": "2026-06-30T10:00:00Z",
  "updated_at": "2026-06-30T10:00:00Z"
}

lead.stage_changed / lead.won / lead.lost — el mismo objeto de lead, más:

{
  "previous_stage_id": 4,
  "new_stage_id": 5,
  "new_stage_name": "Proposta"
}

sale.created

{
  "sale_id": 1,
  "lead_id": 123,
  "pipeline_id": 1,
  "value": 5000.0,
  "closed_by": 12,
  "closed_at": "2026-06-30T10:05:00Z",
  "lead": {
    "id": 123,
    "name": "João Silva",
    "email": "[email protected]",
    "phone": "+5511999887766",
    "company": "ACME",
    "pipeline_id": 1,
    "stage_id": 10,
    "owner": { "id": 12, "name": "Ana", "email": "[email protected]" }
  }
}

task.created / task.updated / task.completed

{
  "id": 45,
  "subject": "Enviar proposta",
  "type": "email",
  "status": "completed",
  "priority": "high",
  "due_date": "2026-07-01",
  "due_time": "09:00",
  "completed_at": "2026-06-30T11:30:00Z",
  "lead_id": 123,
  "assigned_to": 12,
  "created_at": "2026-06-30T08:00:00Z",
  "updated_at": "2026-06-30T11:30:00Z"
}

note.added, nps.answered, lead.assignment_changed, lead.merged y lead.tags_changed siguen el mismo envelope, con el data específico del evento (incluyendo el lead de contexto cuando corresponda).