Webhooks

Los Webhooks son notificaciones automatizadas a URLs definidas, que informan en tiempo real sobre eventos. Son útiles porque permiten una respuesta inmediata a eventos específicos, sin necesidad de una consulta continua. Los Webhooks ayudan a mantener los sistemas eficientes y receptivos.

Sus Webhooks se activan inmediatamente cuando ocurre un evento. Si no podemos alcanzar su URL o si responde con un estado de error, repetimos el envío según un plan fijo y, además, comprobamos automáticamente durante varios días si el receptor está fallando de forma permanente. Encontrará los detalles más abajo en Entrega y reintentos.


Entrega y reintentos

Cuándo reintentamos un Webhook

Un Webhook solo se vuelve a entregar cuando la respuesta de su servidor indica un error temporal:

  • Name
    HTTP 429
    Type
    límite de tasa
    Description

    Su endpoint indica que actualmente está recibiendo demasiadas solicitudes.

  • Name
    HTTP 5xx
    Type
    error de servidor
    Description

    En concreto 500, 502, 503 y 504, además de los códigos de error de origen de Cloudflare 520 a 524 (por ejemplo, 521 "Web Server Is Down", que Cloudflare devuelve en lugar de 502 para dominios con proxy).

  • Name
    Errores de conexión
    Type
    red
    Description

    Tiempos de espera, fallos de resolución DNS, errores de TLS/handshake o una conexión que se interrumpe durante la solicitud.

Todas las demás respuestas se consideran finales y no desencadenan otro intento de entrega. Esto incluye los códigos 4xx como 400, 401, 403 y 404, ya que normalmente indican un error de configuración en el lado del receptor que no se puede solucionar simplemente reintentando. Las respuestas en el rango 2xx y 3xx se consideran exitosas.

Tiempo de espera de la solicitud

Cada intento de entrega tiene un tiempo de espera de 5 segundos. Si su servidor no responde dentro de este margen, tratamos el intento como fallido y programamos un reintento según el plan que se describe a continuación.

Plan de reintentos

Si un intento falla, el siguiente se programa tras un retraso fijo y creciente. Realizamos un total de hasta 14 intentos; después, el trabajo se descarta. La ventana total de entrega abarca por tanto aproximadamente 3,5 días.

IntentoEspera desde el intento anterior
1 (inicial)inmediatamente
21 minuto
35 minutos
430 minutos
560 minutos
62 horas
7 a 1410 horas cada uno

Cada intento se firma por separado y lleva encabezados X-Timestamp, X-Nonce y X-Signature nuevos, véase más abajo Verificar firma.

Desactivación automática en caso de fallos persistentes

Además de los reintentos individuales, supervisamos continuamente la tasa de error diaria por Webhook. Un Webhook se marca como "problemático" en cuanto, en un mismo día,

  • la tasa de error diaria está por encima del 80 % y
  • se han producido al menos 10 errores ese día.

A partir de ese momento, el Webhook se observa durante varios días. Si la situación no mejora, el sistema escala paso a paso:

DíaUmbral (tasa de error rolling)Acción
1por encima del 80 %Correo de aviso nivel 1
3por encima del 85 %Correo de aviso nivel 2
5por encima del 90 %Correo de aviso nivel 3
7por encima del 95 %El Webhook se desactiva automáticamente, entrada en el audit-log y correo de desactivación

Los contadores diarios se cuentan a partir del día en que se detecta el problema.

Tras una desactivación automática

Un Webhook desactivado automáticamente permanece inactivo hasta que lo reactive manualmente en el Dashboard. Tras la reactivación, las estadísticas comienzan de cero.

¿Qué cuenta como "exitoso"?

Para la evaluación de la tasa de error, toda respuesta que no sea un disparador de reintento cuenta como "ok". En concreto, las respuestas 2xx, 3xx e incluso 4xx (excepto 429) se tratan como exitosas, ya que desde la perspectiva del sistema de envío representan una respuesta final y unívoca.


Seguridad

Verificar IP de origen

Todos los Webhooks provienen de nuestra IPv4 195.201.160.143 o de la IPv6 2a01:4f8:13a:8e7::2. Si esto cambia, encontrará todos los detalles adicionales en nuestro Changelog.

Verificar firma

Todos los Webhooks a su servidor se firman con la clave de firma de su cuenta. Con estos datos, puede validar la autenticidad de las solicitudes recibidas de nosotros y evitar duplicaciones o solicitudes fraudulentas. Verifique la firma como se describe en la página Firma.

Le enviamos los siguientes encabezados en cada Webhook:

  • Name
    X-Signature
    Type
    string
    Description

    La firma generada por nosotros

  • Name
    X-Timestamp
    Type
    integer
    Description

    Marca de tiempo en la que la firma fue creada por nosotros

  • Name
    X-Nonce
    Type
    string
    Description

    Cadena generada aleatoriamente con 32 caracteres

Cada intento de entrega se firma por separado. El envío inicial, cada reintento automático del plan de reintentos y un reenvío manual desde el depurador de Webhooks llevan su propio X-Timestamp, su propio X-Nonce y una X-Signature correspondiente. Un reintento que llega horas después del evento sigue llevando, por tanto, una marca de tiempo actual y un nonce que nunca se había utilizado antes.

Por ello, la ventana de 30 segundos para la marca de tiempo y la unicidad del nonce descritas en la página Firma también se aplican sin cambios a los reintentos. Mantenga su ventana de validación en 30 segundos y no la amplíe para los reintentos.


Ejemplos como JSON Payload

SMS

SMS entrante (sms_mo)

{
  "data": {
    "id": "681590",
    "sender": "SMS",
    "system": "491771783130",
    "text": "Hello World",
    "time": "1605878104",
    "message_type": "SMS"
  },
  "webhook_event": "sms_mo",
  "webhook_timestamp": "2020-12-02 11:55:44"
}

Cambio de estado de SMS (dlr)

{
  "data": {
    "msg_id": "77149843739",
    "status": "TRANSMITTED",
    "timestamp": "2021-08-24 08:08:00.000000"
  },
  "webhook_event": "dlr",
  "webhook_timestamp": "2021-08-24T08:08:00+02:00"
}

Seguimiento de Rendimiento (tracking)

{
    "webhook_event": "tracking",
    "webhook_timestamp": "2022-07-27T07:38:18+02:00",
    "data": {
        "sms_id": "77182424125",
        "sms_label": null,
        "tracking_url": "https://svn.me/7oz",
        "final_url": "https://www.google.com",
        "type": "click",
        "total_clicks": 5,
        "total_views": 3
    }
}

Voz

Cambio de estado del mensaje de voz (voice_status)

{
  "data": {
    "callerId": "49176123456789",
    "duration": "4",
    "id": "284195",
    "pricePerMinute": 0.075,
    "recipient": "4943160049851",
    "status": "completed",
    "timestamp": 1629786769
  },
  "webhook_event": "voice_status",
  "webhook_timestamp": "2021-08-24T08:32:50+02:00"
}

Llamada entrante (voice_call)

{
  "webhook_event": "voice_call",
  "webhook_timestamp": "2024-08-02T07:28:59+02:00",
  "data": {
    "id": 0,
    "caller": "4943160049851",
    "time": 1722576539,
    "system": "4915170517246"
  }
}

Señal DTMF (voice_dtmf)

{
  "webhook_event": "voice_dtmf",
  "webhook_timestamp": "2024-08-02T07:28:59+02:00",
  "data": {
    "id": 0,
    "callerId": "4943160049851",
    "recipient": "4943160049851",
    "status": "completed",
    "system": "4915170517246",
    "timestamp": 1722576539,
    "duration": 2.76,
    "pricePerMinute": 0.045,
    "dtmf_digit": 9,
    "total_price": 0.045
  }
}

RCS

Mensaje fue entregado

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T10:01:07+01:00",
  "data":
  {
    "msg_id": "77233699836",
    "status": "DELIVERED",
    "timestamp": "1709888466.254410",
    "foreign_id": null,
    "agent_id": "myfancyagent"
  }
}

Mensaje fue leído

{
    "webhook_event": "rcs",
    "webhook_timestamp": "2024-03-08T10:01:09+01:00",
    "data":
    {
      "msg_id": "77233699836",
      "status": "READ",
      "timestamp": "1709888468.065783",
      "foreign_id": null,
      "agent_id": "myfancyagent"
    }
  }

Informe de estado de un mensaje enviado

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T10:00:18+01:00",
  "data":
  {
    "sender": "4915153952979",
    "status": "IS_TYPING",
    "agent_id": "myfancyagent"
  }
}

Se envió un mensaje de texto

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T09:47:12+01:00",
  "data": {
    "id": 1871353,
    "sender": "4915153952979",
    "time": 1709870553,
    "message_type": "RCS",
    "content_type": "text",
    "text": "Hallo",
    "agent_id": "myfancyagent"
  }
}

Se seleccionó una respuesta sugerida

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T05:59:33+01:00",
  "data": {
    "id": 1870983,
    "sender": "4915153952979",
    "time": 1709870129,
    "message_type": "RCS",
    "content_type": "suggestion_response",
    "suggestion_response": {
      "postbackData": "suggestion_2",
      "text": "Suggestion #2",
      "type": "REPLY"
    },
    "agent_id": "myfancyagent"
  }
}

Se envió una imagen

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T08:58:20+01:00",
  "data": {
    "id": 1871195,
    "sender": "4915153952979",
    "time": 1709870556,
    "message_type": "RCS",
    "content_type": "user_file",
    "user_file": {
      "thumbnail": {
        "mimeType": "image/jpeg",
        "fileSizeBytes": 10166,
        "fileUri": "https://static.seven.io/uploads/rbm/61513d3d/6176746a5177553d/4f36357145416a773452537737696e495a366a68454a42344639574937716e62704156765358664d486e42776730337334675a76522b6d4f574b6e32626632546842493d.jpeg"
      },
      "payload": {
        "mimeType": "image/jpeg",
        "fileSizeBytes": 611314,
        "fileName": "IMG_20240308_050231_01.jpg",
        "fileUri": "https://static.seven.io/uploads/rbm/61513d3d/6176746a5177553d/4f76746e45515768746866717653444e6166336a513852375249614d753637656f414a6f4758624d5358417269306e767331493645372b47446654325a66764b3168453d.jpeg"
      }
    },
    "agent_id": "myfancyagent"
  }
}

Se envió un archivo

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T11:07:51+01:00",
  "data": {
    "id": 1871485,
    "sender": "4915153952979",
    "time": 1709892233,
    "message_type": "RCS",
    "content_type": "user_file",
    "user_file": {
      "payload": {
        "mimeType": "application/pdf",
        "fileSizeBytes": 18810,
        "fileName": "sample (1).pdf",
        "fileUri": "https://static.seven.io/uploads/rbm/61513d3d/617678715267303d/4f616c675256696b73524c6c75337a4b5a66336a51705570464e665a752f6d4e70464d37546e504b5458423730556a7337314e70514c3241436650304d616e4b3078493d.pdf"
      }
    },
    "agent_id": "myfancyagent"
  }
}

Se compartió una ubicación

{
  "webhook_event": "rcs",
  "webhook_timestamp": "2024-03-08T11:07:51+01:00",
  "data": {
    "id": 1871485,
    "sender": "4915153952979",
    "time": 1709892233,
    "message_type": "RCS",
    "content_type": "location",
    "location": {
        "latitude": 54.3216562,
        "longitude": 10.1350767
    },
    "agent_id": "myfancyagent"
  }
}

WhatsApp

Los mensajes de WhatsApp entrantes se entregan con el evento wa_mo. El objeto data contiene siempre los mismos campos base, independientemente de lo que haya enviado el cliente:

  • Name
    id
    Type
    integer
    Description

    ID interno del mensaje entrante

  • Name
    sender
    Type
    string
    Description

    Número de teléfono del remitente en formato internacional sin el signo más inicial

  • Name
    time
    Type
    integer
    Description

    Marca de tiempo Unix de la recepción

  • Name
    text
    Type
    string
    Description

    Contenido del mensaje. Texto plano en mensajes de texto, una cadena codificada en JSON para todos los demás tipos de contenido

  • Name
    message_type
    Type
    string
    Description

    Siempre WA

  • Name
    system
    Type
    string
    Description

    Su número de WhatsApp Business al que se envió el mensaje

Si define un filtro de eventos en el Webhook, este se compara con system. Así puede distribuir los mensajes por número de WhatsApp Business.

Mensaje de texto entrante (wa_mo)

{
  "webhook_event": "wa_mo",
  "webhook_timestamp": "2026-08-21T14:50:12+02:00",
  "data": {
    "id": 4521987,
    "sender": "353861234567",
    "time": 1755780612,
    "text": "Hello World",
    "message_type": "WA",
    "system": "4915170517246"
  }
}

Tipos de contenido distintos del texto plano

Archivos multimedia, ubicaciones, contactos, botones de respuesta rápida y respuestas interactivas se entregan en el mismo sobre. El campo text contiene entonces una cadena codificada en JSON cuya clave type indica qué se ha recibido:

typeEnviado por el cliente
user_fileImagen, vídeo, audio, documento o sticker
locationUna ubicación compartida
contactUna tarjeta de contacto compartida
buttonBotón de respuesta rápida de un mensaje de plantilla
interactiveRespuesta a un mensaje interactivo (botón o lista)

Contenido decodificado del campo text:

Multimedia (user_file)

{
  "type": "user_file",
  "user_file": [
    {
      "type": "image",
      "mediaId": "1234567890123456",
      "mimeType": "image/jpeg",
      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "fileName": "IMG_20260821_145012.jpg",
      "fileUri": "https://static.seven.io/uploads/whatsapp/61513d3d/6176746a/4f36357145416a773452537737/IMG_20260821_145012.jpg",
      "caption": "Mira esto"
    }
  ]
}

type se deriva del tipo MIME y es uno de image, video, audio, document o sticker. Si no podemos descargar el archivo de Meta, falta fileUri y el objeto contiene en su lugar "downloadFailed": true. En ese caso utilice mediaId para obtener el archivo usted mismo.

Ubicación

{
  "type": "location",
  "location": {
    "latitude": 54.3216562,
    "longitude": 10.1350767,
    "name": "seven communications GmbH",
    "address": "Alte Weide 7, 24116 Kiel"
  }
}

Contacto

{
  "type": "contact",
  "contact": {
    "formattedName": "John Doe",
    "firstName": "John",
    "lastName": "Doe",
    "middleName": null,
    "phones": [{"phone": "+353861234567", "type": "CELL"}],
    "emails": [{"email": "john@example.com", "type": "WORK"}],
    "addresses": [],
    "company": "Example Ltd",
    "birthday": "1985-04-12"
  }
}

Botón de respuesta rápida

{
  "type": "button",
  "button": {
    "text": "Confirmar cita",
    "payload": "confirm_2026_08_21"
  }
}

Respuesta interactiva

{
  "type": "interactive",
  "interactive": {
    "item_id": "option_2",
    "title": "Opción #2",
    "description": "Entrega el viernes"
  }
}
Última actualización: Hace 7 horas