Webhooks
Guia de Integração de Webhooks
Receba notificações em tempo real sobre eventos de controle de acesso — criação, atualização, transferência, cancelamento, reembolso e uso de ingressos.
Visão geral
Webhooks permitem que seu sistema seja notificado automaticamente sempre que um evento relevante ocorre na plataforma de controle de acesso da Ingresse. Em vez de consultar a API repetidamente (polling), você registra uma URL e passa a receber requisições HTTP POST com o payload do evento.
Como funciona
Ambientes
| Ambiente | Base URL | Uso |
|---|---|---|
production | <WEBHOOK_PROD_HOST> | Fornecido junto com suas credenciais no onboarding. |
development | https://awa-access-webhook.dev.ingresse.com | Ambiente de testes/homologação. |
Gatilhos disponíveis
Ao criar uma assinatura, escolha um ou mais gatilhos. Cada gatilho corresponde a um tipo de evento.
| Gatilho | event_type | Descrição |
|---|---|---|
create | code_created | Novo código/ingresso criado. |
update | code_updated | Código/ingresso atualizado. |
transfer | code_transferred | Ingresso transferido para outra pessoa. |
cancel | code_cancelled | Ingresso cancelado. |
refund | code_refunded | Ingresso reembolsado. |
use | code_used | Ingresso utilizado (check-in/validação). |
Disponibilidade dos gatilhos
Estrutura do payload
Cada notificação é enviada como POST com corpo JSON. Os campos de topo identificam o evento; payload contém os dados do código/ingresso.
{
"id": 1042,
"event_type": "code_created",
"created_at": "2026-04-29T13:00:12Z",
"payload": {
"attributes": {
"attendee_external_ref": "a7e1c2d4-0000-4000-8000-000000000009",
"locale": "pt-BR",
"original_price_cents": 20000,
"rfc": false
},
"buyer_id": "750e8400-e29b-41d4-a716-446655440000",
"can_transfer": true,
"code": "25ABC12345678",
"created_at": "2026-04-29T13:00:11Z",
"event": {
"banner_image_url": "https://cdn.example.com/evento/banner.jpg",
"external_id": "95a447c4-0000-4000-8000-000000000002",
"id": "850e8400-e29b-41d4-a716-446655440000",
"map_image_url": "https://cdn.example.com/evento/mapa.jpg",
"name": "Evento de Exemplo 2026",
"organization_id": "b10e8400-e29b-41d4-a716-446655440000",
"place_id": "c20e8400-e29b-41d4-a716-446655440000",
"slug": "evento-de-exemplo-2026",
"status": "published",
"timezone": "America/Sao_Paulo",
"type": "party"
},
"event_id": "850e8400-e29b-41d4-a716-446655440000",
"external_id": "ext-code-123",
"id": "550e8400-e29b-41d4-a716-446655440000",
"order_id": "650e8400-e29b-41d4-a716-446655440000",
"owner": {
"birthdate": "1990-01-01",
"document": "00000000000",
"document_type": "cpf",
"email": "[email protected]",
"external_id": "ext-user-4471",
"id": "750e8400-e29b-41d4-a716-446655440000",
"name": "Nome Exemplo",
"phone": "+5511900000000"
},
"owner_id": "750e8400-e29b-41d4-a716-446655440000",
"ownership": "owner",
"status": "active",
"ticket": {
"allotment": "Lote 1",
"allotment_number": 1,
"description": "Ingresso de exemplo",
"external_id": "45b2c9d6-0000-4000-8000-000000000003",
"group": {
"entrance_mapping": "A1-A5",
"entrance_method": "qrcode",
"entrance_name": "Portao A",
"event_dates": [
{
"date": "2026-09-09T22:30:00.000Z",
"event_id": "850e8400-e29b-41d4-a716-446655440000",
"external_id": "e91f2a06-0000-4000-8000-000000000005",
"id": "c70e8400-e29b-41d4-a716-446655440000",
"past": false
}
],
"external_id": "7c3d1e58-0000-4000-8000-000000000004",
"id": "b60e8400-e29b-41d4-a716-446655440000",
"name": "Pista",
"order": 1
},
"group_id": "b60e8400-e29b-41d4-a716-446655440000",
"holder_type": "all",
"id": "950e8400-e29b-41d4-a716-446655440000",
"name": "Inteira",
"order": 0,
"price": 20000,
"transferable": "always"
},
"ticket_id": "950e8400-e29b-41d4-a716-446655440000",
"type": "individual",
"updated_at": "2026-04-29T13:00:11Z",
"user": {
"birthdate": "1990-01-01",
"document": "00000000000",
"document_type": "cpf",
"email": "[email protected]",
"external_id": "ext-user-4471",
"id": "750e8400-e29b-41d4-a716-446655440000",
"name": "Nome Exemplo",
"phone": "+5511900000000"
},
"user_id": "750e8400-e29b-41d4-a716-446655440000"
}
}| event_type | Gatilho | O que muda em relação a code_created |
|---|---|---|
code_created | create | Formato base: status active, user, owner e buyer_id costumam ser a mesma pessoa. |
code_updated | update | Mesmo formato, com o estado novo do código — ex.: attributes.rfc após associar a biometria facial, ou ticket/group após troca de setor. |
code_transferred | transfer | user, owner, user_id e owner_id passam a ser o destinatário. buyer_id continua sendo quem comprou. ownership é recalculado. |
code_cancelled | cancel | status cancelled e can_transfer false. Em cortesias, user/owner podem vir ausentes. |
code_refunded | refund | status refunded e can_transfer false. |
code_used | use | Único com validation_metadata (sessão, tipo de entrada e horário). status continua active. |
| Campo | Tipo | Descrição |
|---|---|---|
id | int | Identificador da notificação. |
event_type | string | Tipo do evento (ex: code_created). |
created_at | string (ISO 8601) | Momento em que a plataforma ingeriu o evento (não necessariamente o instante exato em que ele ocorreu). |
payload | object | Dados do código/ingresso afetado. |
Objeto payload
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID interno do código de acesso. |
code | string | Valor do código apresentado na entrada. |
external_id | string | Identificador do código no sistema de origem. Opcional. |
type | string | individual | passport |
status | string | active | refunded | cancelled — não muda para used após o check-in. |
order_id | string (UUID) | Pedido de origem do código. |
user_id | string (UUID) | Igual a user.id. Opcional. |
owner_id | string (UUID) | Igual a owner.id. Opcional. |
buyer_id | string (UUID) | Comprador. Não existe objeto buyer no payload. |
ownership | string | owner | other | dependent — pode vir ausente. |
event_id | string (UUID) | ID interno do evento — igual a event.id. Não é o UUID das URLs da Access Control. |
ticket_id | string (UUID) | ID interno do ingresso — igual a ticket.id. Vem vazio ("") em códigos de produto. |
can_transfer | boolean | Se o ingresso ainda pode ser transferido. |
created_at | string (RFC3339) | Criação do código. Não é o created_at do envelope. |
updated_at | string (RFC3339) | Última atualização do código. Opcional. |
attributes | object | Atributos adicionais (ver abaixo). Opcional. |
user | object | Usuário associado ao código (ver abaixo). Opcional. |
owner | object | Portador do código (ver abaixo). Opcional. |
event | object | Dados do evento (ver abaixo). Opcional. |
ticket | object | Dados do ingresso (ver abaixo). Ausente em códigos de produto. |
validation_metadata | object | Dados do check-in (ver abaixo). Presente apenas em code_used. |
Os campos de topo acima são um conjunto fechado. Já os objetos aninhados (event, ticket, user, owner, attributes e validation_metadata) são repassados como vêm da origem — podem ganhar campos novos sem aviso. Ignore campos desconhecidos ao processar.
Os objetos aninhados têm os mesmos nomes da Guest List API, mas não são os mesmos: campos e unidades diferem. Use as tabelas abaixo como referência do webhook.
Atenção aos identificadores: o event_id de topo e event.id são o mesmo valor — o ID interno do evento. O UUID usado nas URLs da Access Control API vem em event.external_id. A mesma regra vale para o ingresso: ticket_id de topo é igual a ticket.id (interno) e o identificador externo vem em ticket.external_id. Para correlacionar com chamadas à Access Control API, use sempre os campos external_id.
Objeto payload.event
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID interno do evento — não é o UUID das URLs da Access Control. |
external_id | string (UUID) | UUID do evento — usado como :event_id nas URLs da Access Control. |
name | string | |
slug | string | |
type | string | Categoria do evento (ex.: soccer_game). Não é um conjunto fechado. |
status | string | draft | published | finished | suspended |
timezone | string | Fuso horário do evento (IANA). |
organization_id | string (UUID) | |
place_id | string (UUID) | |
provider_id | string (UUID) | Opcional. |
banner_image_url | string | |
map_image_url | string | |
event_dates | array | Opcional — nem sempre vem preenchido. Todas as sessões do evento, em ordem cronológica. Mesma forma da tabela abaixo, mas outro formato de data. Para as sessões do setor use ticket.group.event_dates[]. |
Objeto payload.ticket
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID interno do tipo de ingresso — igual ao ticket_id de topo. |
external_id | string | Identificador externo do tipo de ingresso. |
group_id | string (UUID) | Igual a group.id. |
name | string | |
description | string | Pode conter HTML. Opcional. |
allotment | string | Lote. |
allotment_number | int | |
price | number | Preço em centavos (ex.: 20000). Na Guest List, price vem em reais. |
transferable | string | always | on_purchase | on_wallet | never |
holder_type | string | all | user_only | dependent — pode vir ausente. |
order | int | |
group | object | Setor do ingresso (ver abaixo). |
Objeto payload.ticket.group
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID interno do setor. |
external_id | string (UUID) | Identificador externo do setor. |
name | string | |
order | int | |
entrance_method | string | face | qrcode |
entrance_name | string | Nome do ponto de entrada. Opcional. |
entrance_mapping | string | Opcional. |
attributes | object | Atributos do setor, mapa chave-valor. Opcional. |
event_dates | array | Sessões a que o setor dá acesso — subconjunto de event.event_dates, sem ordem garantida (ver abaixo). |
Objeto payload.ticket.group.event_dates[]
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID interno da sessão. É o valor de validation_metadata.session_id. |
external_id | string (UUID) | UUID da sessão — usado como :session_id na Validation API. |
date | string | Data e hora da sessão. Os dois níveis usam formatos diferentes: 2026-09-09T22:30:00.000Z aqui e 2026-09-09 22:30:00 em event.event_dates[]. Trate como string, não como RFC 3339. |
event_id | string (UUID) | ID interno do evento ao qual a sessão pertence. |
past | boolean | true quando a sessão já ocorreu. |
Onde está a sessão
Objeto payload.user / payload.owner
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | Igual a user_id / owner_id de topo. |
external_id | string | Identificador da pessoa no sistema de origem. |
name | string | |
email | string | |
phone | string | |
document | string | Documento do titular — CPF quando document_type = cpf. |
document_type | string | Pode vir vazio ("") quando o tipo não é conhecido. |
birthdate | string (YYYY-MM-DD) |
Dados pessoais (LGPD)
Objeto payload.attributes
attributes é um mapa chave-valor aberto: as chaves abaixo são as mais comuns, mas a lista não é exaustiva.
| Campo | Tipo | Descrição |
|---|---|---|
rfc | boolean | Biometria facial ativa para o código. |
rfc_provider | string | Provedor de biometria. |
locale | string | |
freepass | boolean | Cortesia. |
seat | string | Assento, quando o setor é numerado. |
bundle_type | string | Tipo do combo, quando o código vem de um. |
attendee_external_ref | string | Referência do participante no sistema de origem do pedido. Opcional. |
original_price_cents | int | Preço original em centavos. Costuma coincidir com ticket.price. |
Objeto payload.validation_metadata (apenas em code_used)
| Campo | Tipo | Descrição |
|---|---|---|
date | string (RFC3339) | Momento em que o check-in foi registrado. |
entrance_type | string | checkin | checkout |
session_id | string (UUID) | Sessão do check-in. Corresponde a ticket.group.event_dates[].id. Vem vazio ("") em validação de produto. |
Backfill ao criar uma assinatura
Segurança e validação de assinatura
Toda requisição inclui o header X-Signature no formato sha256=<hash>. O hash é um HMAC-SHA256 do corpo bruto da requisição usando o secret da assinatura. Sempre valide a assinatura antes de processar o evento.
O secret é gerado no momento da criação da assinatura e entregue pela Ingresse durante o onboarding.
Além do X-Signature, cada requisição chega com Content-Type: application/json e User-Agent: awa-access-webhook/1.0.
Use o corpo bruto
Requisitos da URL receptora
const crypto = require('crypto')
function verificarAssinatura(segredo, corpo, cabecalho) {
const esperado = Buffer.from('sha256=' + crypto.createHmac('sha256', segredo).update(corpo).digest('hex'))
const recebido = Buffer.from(cabecalho ?? '')
// timingSafeEqual lança se os buffers tiverem tamanhos diferentes — comparar antes.
if (esperado.length !== recebido.length) return false
return crypto.timingSafeEqual(esperado, recebido)
}
// Com Express: use express.raw para receber o corpo bruto
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
if (!verificarAssinatura(process.env.SEGREDO, req.body, req.headers['x-signature'] ?? ''))
return res.status(401).send()
// processar evento de forma assíncrona...
res.status(200).send()
})Idempotência
A mesma notificação pode ser entregue mais de uma vez (por exemplo, após uma reentrega). Use o campo id como chave de idempotência para evitar processamento duplicado. O id do envelope é estável entre reentregas: a mesma notificação sempre chega com o mesmo id.
# Exemplo com Redis (Python)
def processar(evento):
chave = f"webhook:{evento['id']}"
if redis.set(chave, 1, ex=86400, nx=True) is None:
return # já processado
# processar...Reentregas e timeouts
Responda com status 2xx o mais rápido possível (idealmente em poucos segundos) e processe o evento de forma assíncrona. O tempo de resposta considerado é de aproximadamente 25 segundos; acima disso a entrega é tratada como timeout. Respostas 3xx contam como sucesso — prefira responder 2xx diretamente.
Respostas 5xx ou timeout são reentregues automaticamente: a entrega é tentada até 3 vezes no total (a tentativa original mais 2 reentregas), com intervalo fixo de aproximadamente 2 minutos. Respostas 4xx (incluindo 429) são consideradas definitivas e não são reentregues. Após esgotadas as tentativas, a entrega é encaminhada para reprocessamento manual pela Ingresse.
Boas práticas
Filtros
É possível restringir quais eventos sua URL recebe usando o objeto filters na criação da assinatura. Apenas eventos cujo payload corresponda aos filtros são entregues.
| Filtro | Tipo | Descrição |
|---|---|---|
type | string | individual | passport |
status | string | Status do ingresso (ex: cancelled). |
event_id | string (UUID) | Restringe a um evento. Use o ID interno (payload.event_id). |
ticket_id | string (UUID) | Restringe a um tipo de ingresso. Use o ID interno (payload.ticket_id). |
can_transfer | boolean | Somente transferíveis/não transferíveis. |
attributes.rfc | boolean | Biometria facial ativa. |
attributes.rfc_provider | string | Provedor de biometria. |
Filtros usam os IDs internos
Somente ingressos individuais com biometria ativa
{
"filters": {
"type": "individual",
"attributes": {
"rfc": true
}
}
}Somente ingressos com status cancelado
{
"filters": {
"status": "cancelled"
}
}Tipo de ingresso específico, apenas transferíveis
{
"filters": {
"ticket_id": "950e8400-e29b-41d4-a716-446655440000",
"can_transfer": true
}
}Todos os ingressos de um evento com biometria obrigatória
{
"filters": {
"event_id": "850e8400-e29b-41d4-a716-446655440000",
"attributes": {
"rfc": true
}
}
}