Saltar al contenido principal
El motor de webhooks envรญa actualizaciones de calendar, seรฑales y sentimiento directamente a tu endpoint HTTP, con reintentos integrados y opciones de filtrado y transformaciรณn. Usa esta guรญa para comprender el proceso de entrega, la forma del payload y las mejores prรกcticas de integraciรณn.

Descripciรณn general

El servicio de webhooks de datos de Benzinga entrega datos de calendar y seรฑales en tiempo real a tus endpoints de webhook configurados. Cuando se crean, actualizan o eliminan eventos de calendar (ganancias, dividendos, calificaciones, etc.) o seรฑales (actividad de opciones, suspensiones, etc.), el servicio envรญa automรกticamente solicitudes HTTP POST a tu URL de webhook con la carga รบtil de datos. Funciones clave:
  • Alcances configurables para la cobertura de calendar y seรฑales, de modo que solo recibas los datos que necesitas
  • Entregas idempotentes con un encabezado รบnico X-BZ-Delivery y un campo id en la carga รบtil para la deduplicaciรณn
  • Estrategia de reintentos sรณlida que escala desde reintentos exponenciales rรกpidos hasta intentos por hora a largo plazo
  • Transformaciones de content opcionales para alinear las cargas รบtiles con las expectativas de los sistemas posteriores

Entrega de webhooks

Detalles de la solicitud HTTP

  • Mรฉtodo: POST
  • Content-Type: application/json
  • User-Agent: Benzinga-Dispatch/v1.0.0 {build-version}
  • Encabezado personalizado: X-BZ-Delivery - Un UUID รบnico para cada intento de entrega (รบtil para evitar duplicados)

Polรญtica de reintentos

El servicio de webhook de datos implementa un mecanismo de reintentos sรณlido:
  • Fase exponencial: 15 reintentos durante los primeros 5 minutos
  • Reintentos exponenciales adicionales: 11 reintentos mรกs si es necesario
  • Fase de intervalo fijo: 12 reintentos por hora ร— 24 horas/dรญa ร— 7 dรญas (para reintentos a largo plazo)
  • Tiempo mรกximo de espera: 5 minutos entre reintentos en la fase exponencial
  • Tiempo de espera de la solicitud: 30 segundos por solicitud

Requisitos de la respuesta

Tu endpoint de webhook debe devolver uno de los siguientes cรณdigos de estado HTTP:
  • Cรณdigos de รฉxito (200-202, 204): Indican una entrega correcta. No se realizarรกn nuevos intentos.
  • Cรณdigos de error de cliente (401-403): Indican un error de autenticaciรณn/autorizaciรณn. Los reintentos se detendrรกn inmediatamente para evitar mรกs intentos fallidos.
  • Otros cรณdigos (4xx, 5xx): Activarรกn reintentos segรบn la polรญtica de reintentos indicada arriba.
Importante: Tu endpoint debe responder rรกpidamente (idealmente en menos de 30 segundos) para evitar un tiempo de espera (timeout). El motor volverรก a intentarlo en caso de timeout.

Estructura del payload del webhook

Cada envรญo de webhook incluye un payload JSON con la siguiente estructura:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "api_version": "webhook/v1",
  "kind": "data/v2.1/calendar/earnings",
  "data": {
    "action": "Created",
    "id": "60a2368362c99dd8ae0cf4b7",
    "timestamp": "2024-01-15T10:30:00Z",
    "content": {
      "id": "60a2368362c99dd8ae0cf4b7",
      "date": "2024-01-15",
      "date_confirmed": 1,
      "time": "08:00:00",
      "ticker": "AAPL",
      "exchange": "NASDAQ",
      "isin": "US0378331005",
      "cusip": "037833100",
      "name": "Apple Inc.",
      "period": "Q1",
      "period_year": 2024,
      "currency": "USD",
      "eps": "2.18",
      "eps_est": "2.10",
      "revenue": "123900000000",
      "revenue_est": "121000000000"
    }
  }
}

Campos del payload

Campos principales

  • id (string, UUID): Identificador รบnico de esta entrega de webhook. รšsalo para evitar duplicados.
  • api_version (string): Identificador de la versiรณn de la API. Actualmente "webhook/v1".
  • kind (string): Identificador de la ruta del tipo de datos. Consulta Tipos de datos compatibles para ver todos los valores posibles.

Objeto de datos

  • action (string): Tipo de acciรณn del evento. Posibles valores:
    • "Created": Se crearon nuevos datos (valor predeterminado para nuevas claves de webhook)
    • "Updated": Se actualizaron datos existentes
    • "Removed": Se eliminaron datos
    • Nota: Las claves de webhook heredadas pueden recibir valores en minรบsculas: "created", "updated", "removed"
  • id (string): Identificador รบnico del registro de calendar o seรฑal
  • timestamp (string, ISO 8601): Momento en que se generรณ el webhook
  • content (object): Los datos de calendar o seรฑal propiamente dichos. La estructura varรญa segรบn el tipo de datos (consulta Tipos de datos compatibles)

Tipos de datos admitidos

El servicio de webhooks de datos admite los siguientes tipos de calendar y seรฑales:

Tipos de datos del calendar (v2.1)

Tipo de datoKind PathDescripciรณn
Earningsdata/v2.1/calendar/earningsAnuncios de resultados de empresas
Dividendsdata/v2.1/calendar/dividendsDeclaraciones y pagos de dividendos
Ratingsdata/v2.1/calendar/ratingsCalificaciones de analistas y precios objetivo
IPOsdata/v2.1/calendar/iposOfertas pรบblicas iniciales
Guidancedata/v2.1/calendar/guidanceActualizaciones de guidance de empresas
Conferencedata/v2.1/calendar/conferenceConferencias telefรณnicas y presentaciones
Economicsdata/v2.1/calendar/economicsIndicadores y comunicados econรณmicos
Offeringsdata/v2.1/calendar/offeringsOfertas secundarias
Mergers & Acquisitionsdata/v2.1/calendar/maAnuncios de M&A
Retaildata/v2.1/calendar/retailDatos de ventas minoristas
Splitsdata/v2.1/calendar/splitsDesdoblamientos de acciones
FDAdata/v2.1/calendar/fdaAprobaciones y anuncios de la FDA

Tipos de datos de seรฑales (v1)

Tipo de datosKind PathDescripciรณn
Actividad de opcionesdata/v1/signal/option_activityActividad inusual de opciones
WIIMsdata/v1/wiimsDatos de Why Is It Moving (WIIMs)
Transacciones internas de la SECdata/v1/sec/insider_transactions/filingsDeclaraciones de operaciones internas ante la SEC
Operaciones gubernamentalesdata/v1/gov/usa/congressDatos de operaciones del Congreso de EE. UU.

Tipos de datos adicionales (v1)

Tipo de datoRuta KindDescripciรณn
Bulls Say Bears Saydata/v1/bulls_bears_sayAnรกlisis de sentimiento del mercado
Bulls Say Bears Say (Korean)data/v1/bulls_bears_say/koreanSentimiento del mercado coreano
Analyst Insightsdata/v1/analyst/insightsOpiniones y comentarios de analistas
Consensus Ratingsdata/v1/consensus-ratingsCalificaciones de consenso agregadas

Ejemplos de estructuras de contenido

Ejemplo de resultados

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "api_version": "webhook/v1",
  "kind": "data/v2.1/calendar/earnings",
  "data": {
    "action": "Created",
    "id": "60a2368362c99dd8ae0cf4b7",
    "timestamp": "2024-01-15T10:30:00Z",
    "content": {
      "id": "60a2368362c99dd8ae0cf4b7",
      "date": "2024-01-15",
      "date_confirmed": 1,
      "time": "08:00:00",
      "ticker": "AAPL",
      "exchange": "NASDAQ",
      "isin": "US0378331005",
      "cusip": "037833100",
      "name": "Apple Inc.",
      "period": "Q1",
      "period_year": 2024,
      "currency": "USD",
      "eps": "2.18",
      "eps_est": "2.10",
      "eps_prior": "1.88",
      "eps_surprise": "0.08",
      "eps_surprise_percent": "3.81",
      "eps_type": "GAAP",
      "revenue": "123900000000",
      "revenue_est": "121000000000",
      "revenue_prior": "117154000000",
      "revenue_surprise": "2900000000",
      "revenue_surprise_percent": "2.40",
      "importance": 0
    }
  }
}

Ejemplo de dividendos

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "api_version": "webhook/v1",
  "kind": "data/v2.1/calendar/dividends",
  "data": {
    "action": "Created",
    "id": "60a2368362c99dd8ae0cf4b8",
    "timestamp": "2024-01-15T10:30:00Z",
    "content": {
      "id": "60a2368362c99dd8ae0cf4b8",
      "date": "2024-02-15",
      "ticker": "AAPL",
      "exchange": "NASDAQ",
      "isin": "US0378331005",
      "cusip": "037833100",
      "name": "Apple Inc.",
      "currency": "USD",
      "frequency": 4,
      "dividend": "0.24",
      "dividend_prior": "0.23",
      "dividend_type": "Regular",
      "dividend_yield": "0.50",
      "ex_dividend_date": "2024-02-09",
      "payable_date": "2024-02-15",
      "record_date": "2024-02-12",
      "confirmed": true,
      "importance": 0
    }
  }
}

Ejemplo de calificaciones

{
  "id": "550e8400-e29b-41d4-a716-446655440002",
  "api_version": "webhook/v1",
  "kind": "data/v2.1/calendar/ratings",
  "data": {
    "action": "Created",
    "id": "60a2368362c99dd8ae0cf4b9",
    "timestamp": "2024-01-15T10:30:00Z",
    "content": {
      "id": "60a2368362c99dd8ae0cf4b9",
      "date": "2024-01-15",
      "time": "09:00:00",
      "ticker": "AAPL",
      "exchange": "NASDAQ",
      "isin": "US0378331005",
      "cusip": "037833100",
      "name": "Apple Inc.",
      "action_pt": "Maintains",
      "action_company": "Maintains",
      "currency": "USD",
      "rating_current": "Buy",
      "pt_current": "200.00",
      "pt_prior": "195.00",
      "adjusted_pt_current": "200.00",
      "adjusted_pt_prior": "195.00",
      "rating_prior": "Buy",
      "url": "https://www.benzinga.com/...",
      "importance": 0,
      "firm": {
        "name": "Goldman Sachs",
        "id": "123"
      },
      "analyst": {
        "name": "John Doe",
        "id": "456"
      }
    }
  }
}

Ejemplo de actividad en opciones

{
  "id": "550e8400-e29b-41d4-a716-446655440003",
  "api_version": "webhook/v1",
  "kind": "data/v1/signal/option_activity",
  "data": {
    "action": "Creado",
    "id": "60a2368362c99dd8ae0cf4ba",
    "timestamp": "2024-01-15T10:30:00Z",
    "content": {
      "id": "60a2368362c99dd8ae0cf4ba",
      "date": "2024-01-15",
      "time": "10:00:00",
      "ticker": "AAPL",
      "exchange": "NASDAQ",
      "option_symbol": "AAPL240119C00150000",
      "strike": "150.00",
      "expiration": "2024-01-19",
      "type": "call",
      "volume": 10000,
      "open_interest": 50000,
      "premium": "500000.00",
      "importance": 0
    }
  }
}

Acciones de eventos

El servicio de webhooks de datos envรญa eventos para tres tipos de acciones:
  1. Created: Se activa cuando se publican nuevos datos de calendario o de seรฑales
  2. Updated: Se activa cuando se modifican datos existentes
  3. Removed: Se activa cuando se eliminan datos
Nota: El formato de la acciรณn depende de la configuraciรณn de tu webhook:
  • Nuevas claves de webhook: Reciben acciones con mayรบscula inicial ("Created", "Updated", "Removed")
  • Claves de webhook heredadas: Reciben acciones en minรบsculas ("created", "updated", "removed")

Filtrado de contenido

La configuraciรณn de tu webhook puede incluir filtros para controlar los datos que recibes:

Opciones de filtrado

  • Tipos de datos: Filtra por tipos especรญficos de calendario/seรฑal (p. ej., solo ganancias, solo calificaciones)
  • Filtros geogrรกficos: Controla si recibes:
    • Datos del mercado de EE. UU. (AllowUSA)
    • Datos del mercado canadiense (AllowCanada)
    • Datos del mercado indio (AllowIndia) - para datos de WIIMs
  • Filtro de fecha: Excluye datos histรณricos anteriores a una fecha especรญfica (MaxHistoricalDate)

Filtrado por exchange

El servicio filtra automรกticamente por exchange en funciรณn de tu configuraciรณn geogrรกfica:
  • Exchanges de EE. UU.: NYSE, NASDAQ, AMEX, ARCA, OTC, OTCBB, PINX, PINK, BATS, IEX
  • Exchanges canadienses: TSX, TSXV, CSE, CNSX

Transformaciรณn de contenido

El motor de webhooks admite la transformaciรณn de contenido para tipos de datos especรญficos. Las transformaciones se aplican segรบn la configuraciรณn del webhook y pueden incluir:
  • Cambio de nombre de campos
  • Conversiรณn de formato de datos
  • Filtrado/eliminaciรณn de campos

Prรกcticas recomendadas

1. Idempotencia

Utilice el campo id (UUID) del payload para implementar la idempotencia. Almacene los ID de entregas ya procesadas para evitar procesarlas mรกs de una vez.

2. Gestiรณn de respuestas

  • Devolver 200 OK o 204 No Content inmediatamente tras recibir el webhook
  • Procesar los datos de forma asรญncrona si es necesario
  • No ejecutar operaciones de larga duraciรณn antes de responder

3. Gestiรณn de errores

  • Devolver cรณdigos de estado HTTP apropiados
  • Para errores de autenticaciรณn (401-403), asegurarse de que el endpoint estรฉ configurado correctamente
  • Para fallos temporales, devolver cรณdigos de estado 5xx para activar reintentos

4. Seguridad

  • Usa HTTPS para tu endpoint de webhook
  • Implementa autenticaciรณn y autorizaciรณn (claves de API, tokens, etc.)
  • Valida el encabezado X-BZ-Delivery para mayor seguridad

5. Supervisiรณn

  • Supervisa los tiempos de respuesta de tu endpoint
  • Configura alertas para fallos reiterados
  • Realiza un seguimiento del encabezado X-BZ-Delivery para identificar intentos de entrega

6. Gestiรณn de tipos de datos

  • Comprueba el campo kind para determinar el tipo de dato
  • Analiza el objeto content segรบn la estructura de ese tipo de dato
  • Gestiona diferentes formatos de acciรณn (mayรบsculas vs. minรบsculas) si se admiten claves heredadas

Ejemplo de controlador de webhook

Python (Flask)

from flask import Flask, request, jsonify
import uuid

app = Flask(__name__)
processed_ids = set()

@app.route('/webhook', methods=['POST'])
def webhook():
    # Obtener ID de entrega para deduplicaciรณn
    delivery_id = request.headers.get('X-BZ-Delivery')
    
    # Analizar carga รบtil
    payload = request.json
    content_id = payload['id']
    
    # Verificar duplicados
    if content_id in processed_ids:
        return jsonify({'status': 'duplicate'}), 200
    
    # Procesar datos
    action = payload['data']['action']
    kind = payload['kind']
    content = payload['data']['content']
    
    print(f"Received {action} event for {kind}")
    print(f"Data ID: {content.get('id')}")
    
    # Gestionar diferentes tipos de datos
    if 'earnings' in kind:
        print(f"Earnings: {content.get('ticker')} - {content.get('date')}")
    elif 'ratings' in kind:
        print(f"Rating: {content.get('ticker')} - {content.get('rating_current')}")
    elif 'option_activity' in kind:
        print(f"Option Activity: {content.get('ticker')} - {content.get('volume')}")
    
    # Marcar como procesado
    processed_ids.add(content_id)
    
    # Retornar รฉxito inmediatamente
    return jsonify({'status': 'received'}), 200

Node.js (Express)

const express = require('express');
const app = express();
app.use(express.json());

const processedIds = new Set();

app.post('/webhook', (req, res) => {
  // Obtener ID de entrega para deduplicaciรณn
  const deliveryId = req.headers['x-bz-delivery'];
  
  // Analizar carga รบtil
  const payload = req.body;
  const contentId = payload.id;
  
  // Verificar duplicados
  if (processedIds.has(contentId)) {
    return res.status(200).json({ status: 'duplicate' });
  }
  
  // Procesar datos
  const { action, content } = payload.data;
  const kind = payload.kind;
  
  console.log(`Received ${action} event for ${kind}`);
  console.log(`Data ID: ${content.id}`);
  
  // Gestionar diferentes tipos de datos
  if (kind.includes('earnings')) {
    console.log(`Earnings: ${content.ticker} - ${content.date}`);
  } else if (kind.includes('ratings')) {
    console.log(`Rating: ${content.ticker} - ${content.rating_current}`);
  } else if (kind.includes('option_activity')) {
    console.log(`Option Activity: ${content.ticker} - ${content.volume}`);
  }
  
  // Marcar como procesado
  processedIds.add(contentId);
  
  // Devolver respuesta exitosa inmediatamente
  res.status(200).json({ status: 'received' });
});

app.listen(3000);
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "sync"
)

var (
    processedIDs = make(map[string]bool)
    mu           sync.RWMutex
)

type WebhookPayload struct {
    ID         string `json:"id"`
    APIVersion string `json:"api_version"`
    Kind       string `json:"kind"`
    Data       struct {
        Action    string                 `json:"action"`
        ID        string                 `json:"id"`
        Timestamp string                 `json:"timestamp"`
        Content   map[string]interface{} `json:"content"`
    } `json:"data"`
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    // Obtener ID de entrega
    deliveryID := r.Header.Get("X-BZ-Delivery")
    
    // Parsear payload
    var payload WebhookPayload
    if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // Verificar duplicados
    mu.RLock()
    if processedIDs[payload.ID] {
        mu.RUnlock()
        w.WriteHeader(http.StatusOK)
        json.NewEncoder(w).Encode(map[string]string{"status": "duplicate"})
        return
    }
    mu.RUnlock()
    
    // Procesar datos
    fmt.Printf("Received %s event for %s\n", payload.Data.Action, payload.Kind)
    fmt.Printf("Data ID: %s\n", payload.Data.ID)
    
    // Manejar diferentes tipos de datos
    content := payload.Data.Content
    if ticker, ok := content["ticker"].(string); ok {
        fmt.Printf("Ticker: %s\n", ticker)
    }
    
    // Marcar como procesado
    mu.Lock()
    processedIDs[payload.ID] = true
    mu.Unlock()
    
    // Retornar รฉxito
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]string{"status": "received"})
}

func main() {
    http.HandleFunc("/webhook", webhookHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Soluciรณn de problemas

Problemas comunes

  1. No se reciben webhooks
    • Verifica que la URL de tu webhook estรฉ configurada correctamente
    • Comprueba que tu endpoint sea accesible pรบblicamente
    • Asegรบrate de que tu API key sea vรกlida y estรฉ activa
    • Verifica que los filtros no estรฉn excluyendo todos los tipos de datos
    • Comprueba que tus filtros geogrรกficos coincidan con los datos que esperas
  2. Entregas duplicadas
    • Implementa idempotencia usando el campo id
    • Revisa los tiempos de respuesta de tu endpoint (las respuestas lentas pueden provocar reintentos)
  3. Errores de autenticaciรณn (401-403)
    • Verifica la configuraciรณn de autenticaciรณn de tu endpoint
    • Comprueba las API keys y los tokens
    • Nota: Los errores de autenticaciรณn detienen los reintentos inmediatamente
  4. Errores de tiempo de espera (timeout)
    • Asegรบrate de que tu endpoint responda en menos de 30 segundos
    • Procesa los datos de forma asรญncrona si es necesario
    • Devuelve una respuesta de รฉxito inmediatamente y procesa despuรฉs
  5. Formato de acciรณn inesperado
    • Comprueba si estรกs usando una webhook key antigua (acciones en minรบsculas)
    • Actualiza a una webhook key nueva para recibir acciones con mayรบscula inicial
    • Maneja ambos formatos si das soporte a mรบltiples clientes
  6. Tipos de datos que faltan
    • Verifica que la configuraciรณn de tu webhook incluya los tipos de datos deseados
    • Revisa los filtros geogrรกficos (configuraciones US/Canada/India)
    • Asegรบrate de que los filtros de fecha no estรฉn excluyendo datos recientes

Soporte

Para consultas o problemas relacionados con la entrega de webhooks:

Historial de versiones

  • v1.0.0: Lanzamiento inicial del servicio de webhooks de datos
  • Versiรณn actual: Mecanismos mejorados de filtrado, transformaciรณn y reintentos