Artículos sobre: Organizadores
Este artículo también está disponible en:

Webhooks

Los webhooks permiten recibir notificaciones en tiempo real en tu propio sistema cuando se producen determinadas acciones en go&dance, como cuando se crea o actualiza una compra.


En lugar de consultar periódicamente go&dance para comprobar si se han producido cambios, puedes configurar una URL de destino a la que go&dance enviará automáticamente una petición HTTP cada vez que ocurra uno de los eventos compatibles con la integración.


Una vez que los webhooks estén activados para tu cuenta, se aplicarán a todos los eventos de los que seas propietario. No es necesario configurar los webhooks por separado para cada evento.


Cada notificación incluye información sobre el evento que la ha generado y los datos correspondientes, lo que te permite integrar go&dance con tus propias aplicaciones, bases de datos, CRM, ERP u otros sistemas externos.


Importante: los webhooks solo se generan para los eventos de los que tu usuario es propietario. Los eventos a los que tengas acceso o que puedas gestionar, pero de los que no seas propietario, no están incluidos.


Índice




Cuando ocurre uno de los eventos suscritos por un webhook activo, go&dance envía una solicitud HTTP a la URL de destino configurada.


La solicitud contiene:


  • Cabeceras con información sobre el evento y la entrega.
  • Un body con formato JSON que contiene los datos del evento.
  • Una firma HMAC-SHA256 que permite verificar que la solicitud fue generada por go&dance.


Cabeceras de la solicitud


Las cabeceras específicas enviadas por go&dance son:


Cabecera

Descripción

X-GoDance-Log-Id

Identificador único de la acción que desencadenó el webhook. Se mantiene igual en los reintentos y debe usarse para evitar procesar la misma acción más de una vez.

X-GoDance-Delivery-Id

Identificador único de un intento de entrega. Cada reintento genera un identificador nuevo.

X-GoDance-Signature

Firma HMAC-SHA256 utilizada para verificar la autenticidad de la solicitud.

X-GoDance-Timestamp

Marca de tiempo utilizada como parte del cálculo de la firma.

X-GoDance-Type

Tipo de evento que desencadenó la notificación.


Ejemplo:


User-Agent: GoDance/Webhooks
Content-Type: application/json
X-GoDance-Log-Id: 2d0df0a0-63c5-48bc-8484-535a5fb0aad6
X-GoDance-Delivery-Id: 6d498a41-d1ad-4ccc-8abf-1045cc52cbac
X-GoDance-Signature: 8ae2fe919f8412ed9001397356a38fa19c4939235511c7a550041454b628473c
X-GoDance-Timestamp: 1790245818
X-GoDance-Type: PURCHASE.UPDATED


X-GoDance-Log-Id


Identifica de forma única la acción que desencadenó el webhook.


La misma acción puede tener varios intentos de entrega. Por ejemplo, si una entrega falla y se reintenta más tarde, todos esos intentos corresponden al mismo
X-GoDance-Log-Id.


Tu integración debe usar este valor para evitar procesar la misma acción más de una vez.


X-GoDance-Delivery-Id


Identifica un intento de entrega concreto.


Si se reintenta la entrega de un webhook, se generará un nuevo X-GoDance-Delivery-Id, mientras que el X-GoDance-Log-Id se mantendrá igual.


Por tanto:


Acción
X-GoDance-Log-Id: A
│
├── Entrega 1 → X-GoDance-Delivery-Id: B
│
├── Entrega 2 → X-GoDance-Delivery-Id: C
│
└── Entrega 3 → X-GoDance-Delivery-Id: D


Usa X-GoDance-Log-Id, no X-GoDance-Delivery-Id, como clave de idempotencia.


X-GoDance-Type


Indica el evento que desencadenó la notificación.


Por ejemplo:


PURCHASE.CREATED


El mismo tipo se incluye en la propiedad type del cuerpo de la solicitud.


X-GoDance-Timestamp


Marca de tiempo generada para la entrega.


Este valor forma parte de los datos usados para calcular la firma.


X-GoDance-Signature


Firma HMAC-SHA256 generada con el secreto del webhook.


Debes validar esta firma antes de procesar la información recibida.



Validar la firma


Cada webhook tiene un secreto con un formato similar a:


gd_sec_********************************


go&dance utiliza este secreto para generar una firma HMAC-SHA256 para cada entrega.


La firma se calcula mediante la siguiente concatenación:


{deliveryId}|{timestamp}|{body}


donde:


  • deliveryId es el valor de X-GoDance-Delivery-Id.
  • timestamp es el valor de X-GoDance-Timestamp.
  • body es exactamente el cuerpo original de la solicitud tal como se recibió en la solicitud HTTP.


El cálculo equivale a:


HMAC-SHA256(
deliveryId + "|" + timestamp + "|" + body,
secret
)


El resultado debe coincidir con:


X-GoDance-Signature


Importante: usa siempre el cuerpo original


Para validar correctamente la firma, debes utilizar el cuerpo original de la solicitud exactamente como se recibió.


No analices, transformes, modifiques ni reserialices el JSON antes de calcular la firma.


Por ejemplo, este flujo es incorrecto:


Cuerpo recibido
↓
JSON.parse(...)
↓
JSON.stringify(...)
↓
Calcular firma ❌


Aunque el JSON resultante represente exactamente los mismos datos, su representación puede haber cambiado.


Cambios aparentemente irrelevantes, como espacios, saltos de línea, escape de caracteres u orden de las propiedades, pueden producir contenido distinto y, por
tanto, una firma HMAC diferente.


El flujo correcto es:


Cuerpo original recibido
│
├──────────────► Calcular y validar firma
│
▼
JSON.parse(...)
│
▼
Procesar evento


Primero valida la firma usando el cuerpo original. Después puedes analizar y procesar el JSON.



Ejemplo en TypeScript


El siguiente ejemplo utiliza un servidor HTTP de Node.js y conserva el cuerpo original antes de convertirlo a JSON:


import crypto from 'node:crypto';

const secret = 'gd_sec_...';

// Obtener las cabeceras
const deliveryId = request.headers['x-godance-delivery-id'];
const timestamp = request.headers['x-godance-timestamp'];
const signature = request.headers['x-godance-signature'];
const logId = request.headers['x-godance-log-id'];

// IMPORTANTE: obtener el cuerpo original sin analizarlo ni serializarlo
const rawBody = request.rawBody;

// Calcular la firma esperada
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(`${deliveryId}|${timestamp}|${rawBody}`)
.digest('hex');

// Validar la firma
if (signature !== expectedSignature) {
return response.status(401).send('Firma no válida');
}

// Evitar procesar la misma acción dos veces
if (await alreadyProcessed(logId)) {
return response.status(200).send('OK');
}

// Una vez validada la firma, podemos analizar el cuerpo
const payload = JSON.parse(rawBody);

await processWebhook(payload);
await markAsProcessed(logId);

return response.status(200).send('OK');


Si usas Express, NestJS u otro framework que transforma automáticamente el cuerpo de la solicitud, asegúrate de conservar el cuerpo sin procesar antes de
que el framework lo procese. La firma siempre debe calcularse usando los bytes originales recibidos.



Evitar el procesamiento duplicado


Los webhooks deben procesarse de forma idempotente.


La misma acción puede generar varios intentos de entrega si, por ejemplo, un intento anterior falló.


Cada intento tendrá un X-GoDance-Delivery-Id diferente, pero todos compartirán el mismo:


X-GoDance-Log-Id


Por tanto, debes usar X-GoDance-Log-Id para determinar si una acción ya se ha procesado.


Una estrategia habitual es:


  1. Recibir el webhook y validar su firma.
  2. Comprobar si el X-GoDance-Log-Id ya existe en tu sistema.
  3. Si ya existe, no ejecutar la operación de nuevo.
  4. Si no existe, procesar el evento y guardar el X-GoDance-Log-Id.


No uses X-GoDance-Delivery-Id como clave de idempotencia. Un reintento de la misma acción tendrá un identificador de entrega diferente.



Respuesta del endpoint


go&dance considera satisfactoria cualquier respuesta HTTP con un código de estado 2xx.


Por ejemplo:


200 OK
201 Created
202 Accepted
204 No Content


Cualquier respuesta 2xx se considera una entrega satisfactoria.


Las respuestas fuera del rango 2xx se consideran entregas fallidas y aparecerán como tales en los registros de webhooks.



Payload


El cuerpo de la solicitud se envía en formato JSON:


Content-Type: application/json


Su estructura general es:


{
  "type": "PURCHASE.UPDATED",
  "data": {
    ...
  }
}


Actualmente están disponibles los siguientes eventos:


Evento

Payload

Descripción

PURCHASE.CREATED

PurchaseDto

Se desencadena al crear una compra, ya sea en línea o presencial.

PURCHASE.UPDATED

PurchaseDto

Se desencadena al actualizar una compra.

PURCHASE.DELETED

ProductDeletedDto

Se desencadena al eliminar un producto de una compra.


Payload es la estructura de datos recibida en el campo data.



Estructuras de datos


PurchaseDto


Campo

Tipo

Obligatorio

Descripción

uuid

string

Sí

Identificador único de la compra.

recordLocator

string

Sí

Localizador de la compra. Es el identificador que el usuario ve en su compra.

event

EventDto

Sí

Evento asociado a la compra.

buyer

BuyerDto

No

Información del comprador.

type

string

Sí

Origen de la compra. Puede contener manual para pedidos generados manualmente u online para compras realizadas en la plataforma.

amount

number

Sí

Importe de la compra. Incluye todos los cargos adicionales, como gastos de gestión, seguro de cancelación, etc.

promoterCode

string

No

Código de promotor asociado, cuando corresponda.

discountCode

string

No

Código de descuento asociado, cuando corresponda.

products

ProductDto[]

Sí

Productos incluidos en la compra.

createdAt

string

Sí

Fecha de creación de la compra.


EventDto


Campo

Tipo

Obligatorio

Descripción

uuid

string

Sí

Identificador único del evento.

customId

string

No

Identificador personalizado del evento, si está disponible.

name

string

Sí

Nombre del evento.


BuyerDto


Campo

Tipo

Obligatorio

name

string

Sí

email

string

Sí


La propiedad buyer puede estar ausente o tener un valor null.


ProductDto


Cada producto tiene la siguiente estructura:


Campo

Tipo

Obligatorio

Descripción

uuid

string

Sí

Identificador único del producto.

ticketCode

string

No

Localizador del producto. Es el identificador que el usuario ve en su compra y el código usado para escanear la entrada con la aplicación móvil.

type

string

Sí

Tipo de producto. Los valores posibles incluyen ticket, distribution-fee, gateway-fee, cancellation-insurance u otros.

status

CANCELED

Sí

Estado del producto.

onBehalfOfOrganization

boolean

Sí

Indica si el producto pertenece al organizador o es un producto de go&dance, como los gastos de distribución.

ticket

TicketDto

No

Información de la entrada, cuando corresponda.

amount

number

Sí

Precio del producto. Es el precio de venta que tú, como organizador, has establecido para el producto.

refundedAmount

number

Sí

Si se han emitido reembolsos, el importe reembolsado al usuario por este producto.

platformFee

number

Sí

Comisión de la plataforma. Es la comisión cobrada al organizador por la venta de esta entrada al procesar la liquidación.

attendees

AttendeeDto[]

Sí

Asistentes asociados al producto.


Los productos con onBehalfOfOrganization = true son productos vendidos en nombre del organizador, como las entradas del evento. En estos casos,
el organizador es responsable de la venta y, cuando corresponda, de emitir la factura correspondiente al comprador.


Los productos con onBehalfOfOrganization = false son productos o servicios vendidos directamente por go&dance. En estos casos, go&dance es responsable
de su gestión y de la facturación correspondiente. Normalmente son conceptos como **gastos de gestión, Cancelación Flexible u otros servicios ofrecidos

por go&dance**.


PurchaseDeletedDto


Campo

Tipo

Obligatorio

Descripción

uuid

string

Sí

Identificador único de la compra.

recordLocator

string

Sí

Localizador de la compra. Es el identificador que el usuario ve en su compra.

productUuid

string

Sí

Identificador único del producto.

ticketCode

string

Sí

Localizador del producto. Es el identificador que el usuario ve en su compra y el código usado para escanear la entrada con la aplicación móvil.


El evento PURCHASE.DELETED se envía mediante POST cada vez que se elimina una entrada de una compra. El campo data contiene un DeletedProductDto con los identificadores de la compra y del producto eliminado.


Si se eliminan varias entradas de una misma compra, go&dance envía una petición de webhook independiente por cada entrada eliminada. Por ejemplo, si se eliminan tres entradas de una misma compra, se generarán tres peticiones PURCHASE.DELETED, cada una con el productUuid y el ticketCode de la entrada eliminada correspondiente.


Importante: no asumas que una única petición PURCHASE.DELETED representa todas las entradas eliminadas de una compra. Procesa cada petición de forma independiente.


Tipos de producto


Los tipos de producto actualmente en uso incluyen:


ticket
distribution-fee
gateway-fee
cancellation-insurance


La integración debe estar preparada para recibir otros valores de type en el futuro.


No asumas que todos los productos son entradas. Según el type, propiedades como ticket pueden estar ausentes o tener valor null.


TicketDto


Cuando el producto corresponde a una entrada, ticket contiene:


Campo

Tipo

Obligatorio

uuid

string

Sí

customId

string null

No

name

string

Sí


AttendeeDto


Cada elemento de attendees tiene la siguiente estructura:


Campo

Tipo

Obligatorio

Descripción

uuid

string

Sí

Identificador único del asistente.

position

number

Sí

Posición del asistente dentro del producto.

completed

boolean

Sí

Indica si la información del asistente está completa.

values

object

Sí

Valores asociados a los campos de información del asistente.


El contenido de values es dinámico y depende de la información solicitada para la entrada.


Por ejemplo:


{
  "fullName": "Asistente de ejemplo",
  "email": "attendee@example.com",
  "gender": "male",
  "role": "leader",
  "residenceCountry": "IT",
  "phone": "+00 000 000 000"
}


La integración no debe asumir que estas propiedades siempre estarán presentes ni que son las únicas propiedades disponibles.



Asociar eventos y entradas de go&dance con tus propios ID


Si integras go&dance con tu propio sistema, puedes usar ID personalizados (customId) para asociar los eventos y entradas de go&dance con los registros
correspondientes de tu base de datos.


Puedes asignar tu propio ID alfanumérico a cada evento y a cada tipo de entrada. Esto te permite identificarlos mediante las mismas referencias que ya usas
en tu sistema.


También puedes guardar los valores de uuid de go&dance en tu base de datos y usar esos identificadores para la asociación. Puedes elegir el enfoque que
mejor se adapte a tu integración.


Configurar el ID personalizado de un evento


Para asignar tu propio ID a un evento, ve a:


Página del evento > Configuración > Información adicional del evento


Introduce tu identificador en el campo ID personalizado.


Este valor se devuelve en el payload del webhook como:


event.customId


Por ejemplo:


{
  "event": {
    "uuid": "goanddance-event-uuid",
    "customId": "MY-EVENT-2026",
    "name": "Mi evento"
  }
}


Después puedes usar uuid o customId para asociar el evento con el evento correspondiente de tu base de datos.


Configurar el ID personalizado de una entrada


También puedes asignar tu propio ID a cada tipo de entrada.


Edita la entrada y abre la pestaña Avanzado. Introduce tu identificador en el campo ID personalizado.


Este valor se devuelve en el payload del webhook dentro de ticket:


products[].ticket.customId


Por ejemplo:


{
  "ticket": {
    "uuid": "goanddance-ticket-uuid",
    "customId": "FULL-PASS-2026",
    "name": "Pase completo"
  }
}


Esto permite asociar cada tipo de entrada de go&dance con el producto, entrada o registro correspondiente de tu propia base de datos.


¿Qué identificador debo usar?


Ambos enfoques son válidos:


  • Usa customId si quieres que go&dance devuelva los identificadores que ya utilizas en tu propio sistema.
  • Usa uuid si prefieres guardar los identificadores de go&dance en tu base de datos y utilizarlos para crear la asociación.


Por ejemplo:


Tu base de datos                go&dance
────────────────────────────────────────────
Evento EVT-2026 ←────→ event.customId
Pase completo FP-01 ←────→ ticket.customId


o:


Tu base de datos                go&dance
────────────────────────────────────────────
Evento ←────→ event.uuid
Tipo de entrada ←────→ ticket.uuid


Importante: customId es opcional. Por tanto, tu integración no debe asumir que siempre tendrá un valor. Si dependes de customId para asociar registros
entre sistemas, asegúrate de haberlo configurado para los eventos y entradas correspondientes.



Seguridad y buenas prácticas


Para una integración segura y fiable:


  • Usa HTTPS para la URL de destino.
  • Guarda el secreto del webhook de forma segura.
  • No expongas el secreto en código del lado cliente ni en repositorios públicos.
  • Valida siempre X-GoDance-Signature antes de procesar el payload.
  • Calcula la firma exclusivamente usando el cuerpo original recibido, sin analizarlo ni reserializarlo.
  • Usa una comparación resistente a ataques de temporización al verificar la firma.
  • Usa X-GoDance-Log-Id como clave de idempotencia.
  • No uses X-GoDance-Delivery-Id para detectar acciones duplicadas.
  • No asumas que los tipos de producto están limitados a los valores conocidos actualmente.
  • Regenera el secreto si crees que puede haberse visto comprometido.

Actualizado el: 29/09/2026

¿Este artículo te resultó útil?

Comparte tu opinión

Cancelar

¡Gracias!