Desenvolvedores · v1.0.0
API do IngressoJá
Ligue a catraca, o CRM, o ERP ou os seus relatórios aos eventos vendidos no IngressoJá: eventos, pedidos, ingressos, check-in e avisos em tempo real por webhook.
Começando
- No painel do IngressoJá, abra Integrações › API e crie um token. Escolha as permissões: leitura (eventos, pedidos e ingressos) e/ou check-in (validar ingresso na entrada).
- Copie o token na hora: ele aparece uma única vez. Se perder, revogue e crie outro.
- Faça as chamadas para
https://api.ingressoja.com/v1.
curl "https://api.ingressoja.com/v1/events" -H "Authorization: Bearer SEU_TOKEN"
Autenticação
Envie o token no cabeçalho Authorization: Bearer ij_... (ou X-Api-Token). Cada token só enxerga os eventos da conta em que foi criado. Use um token por sistema (ex.: um para a catraca, outro para o CRM): assim você revoga um sem parar os outros, e o painel mostra o último uso de cada um.
Nunca coloque o token em site, app ou código que roda no navegador do cliente: ele dá acesso aos dados dos seus compradores.
Formato e paginação
- Respostas em JSON, sempre com o conteúdo em
data. - Valores em centavos (
5000= R$ 50,00). Datas em ISO 8601, UTC; o fuso dos eventos éAmerica/Sao_Paulo. - O
idde um evento é o código do link dele (ingressoja.com/eventos/89646811269). - Listas são paginadas por cursor:
?limit=(1 a 200, padrão 50). Quandopagination.has_morefor true, peça a próxima página com?cursor=+pagination.next_cursor.
Erros e limites
Erros vêm como { "error": { "code": "...", "message": "..." } }. Limite: 120 pedidos por minuto por token.
| 400 | invalid_status / invalid_date / invalid_session | Parâmetro com valor inválido. |
| 401 | missing_token / invalid_token | Token ausente, errado ou revogado. |
| 403 | insufficient_scope | O token não tem a permissão da rota (leitura ou check-in). |
| 404 | event_not_found / order_not_found / ticket_not_found | Não existe, ou não é da sua conta. |
| 429 | rate_limited | Mais de 120 pedidos por minuto com o mesmo token. |
Endpoints
Base: https://api.ingressoja.com/v1
/eventspermissão: leituraListar eventos
Eventos da sua conta, do mais próximo para o mais distante. Para os setores de cada evento, use “Buscar evento”.
| Parâmetro | Onde | Descrição |
|---|---|---|
| status | query | Situação do evento.published | upcoming | draft | cancelled |
| from | query | Só eventos que começam a partir desta data (AAAA-MM-DD ou ISO 8601). |
| limit | query | Itens por página, de 1 a 200. Padrão: 50. |
| cursor | query | Valor de pagination.next_cursor da página anterior. |
Requisição
curl "https://api.ingressoja.com/v1/events?status=published" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": [
{
"id": "89646811269",
"internal_id": "6a1f2c9e-0b5d-4e2a-9c41-3f8e7d2b1a90",
"name": "Danilo & Davi",
"subtitle": null,
"category": "Show",
"kind": "single",
"status": "published",
"sales_paused": false,
"starts_at": "2026-11-06T02:00:00.000Z",
"ends_at": null,
"gates_open_at": "2026-11-05T23:00:00.000Z",
"sales_start_at": null,
"timezone": "America/Sao_Paulo",
"age_rating": "18",
"image_url": "https://ingressoja.com/s3/ingressoja/public/eventos/danilo-e-davi.webp",
"url": "https://ingressoja.com/eventos/89646811269",
"venue": {
"name": "Villa Country",
"city": "São Paulo",
"state": "SP",
"address": {
"street": "Av. Francisco Matarazzo",
"number": "774",
"district": "Barra Funda",
"zip_code": "05001100"
}
},
"sessions": [],
"created_at": "2026-10-17T23:51:10.000Z",
"updated_at": "2026-10-18T14:02:44.000Z"
}
],
"pagination": {
"limit": 50,
"has_more": true,
"next_cursor": "4a088077-e3c4-4fff-a87a-2fa706b36664"
}
}/events/{id}permissão: leituraBuscar evento
Um evento com setores, preços (centavos), vendidos e disponíveis. Festivais trazem os dias em sessions.
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": {
"id": "89646811269",
"internal_id": "6a1f2c9e-0b5d-4e2a-9c41-3f8e7d2b1a90",
"name": "Danilo & Davi",
"subtitle": null,
"category": "Show",
"kind": "single",
"status": "published",
"sales_paused": false,
"starts_at": "2026-11-06T02:00:00.000Z",
"ends_at": null,
"gates_open_at": "2026-11-05T23:00:00.000Z",
"sales_start_at": null,
"timezone": "America/Sao_Paulo",
"age_rating": "18",
"image_url": "https://ingressoja.com/s3/ingressoja/public/eventos/danilo-e-davi.webp",
"url": "https://ingressoja.com/eventos/89646811269",
"venue": {
"name": "Villa Country",
"city": "São Paulo",
"state": "SP",
"address": {
"street": "Av. Francisco Matarazzo",
"number": "774",
"district": "Barra Funda",
"zip_code": "05001100"
}
},
"sessions": [],
"created_at": "2026-10-17T23:51:10.000Z",
"updated_at": "2026-10-18T14:02:44.000Z",
"sectors": [
{
"id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"name": "Pista",
"group": null,
"kind": "full",
"session_id": null,
"passport": false,
"price": 5000,
"capacity": 2000,
"sold": 812,
"available": 1170,
"active": true
},
{
"id": "c3a1d1bb-2d3e-4f60-9bac-1d2e3f4a5b6c",
"name": "Camarote Villa Country",
"group": null,
"kind": "full",
"session_id": null,
"passport": false,
"price": 12000,
"capacity": 300,
"sold": 214,
"available": 80,
"active": true
}
]
}
}/events/{id}/orderspermissão: leituraListar pedidos
Pedidos do evento, do mais recente para o mais antigo, com comprador, itens, valores e origem (UTM).
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
| status | query | Situação do pedido.paid | pending | cancelled | refunded | expired |
| query | E-mail do comprador. | |
| from | query | Pedidos feitos a partir desta data. |
| to | query | Pedidos feitos até esta data. |
| limit | query | Itens por página, de 1 a 200. Padrão: 50. |
| cursor | query | Valor de pagination.next_cursor da página anterior. |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269/orders?status=paid&limit=50" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": [
{
"id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"number": "7D2C1B0A",
"event_id": "89646811269",
"status": "paid",
"channel": "online",
"payment_method": "pix",
"installments": null,
"created_at": "2026-10-18T15:18:40.000Z",
"paid_at": "2026-10-18T15:20:03.000Z",
"cancelled_at": null,
"buyer": {
"name": "Maria Souza",
"email": "maria@email.com",
"phone": "11999990000"
},
"items": [
{
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"quantity": 2,
"unit_price": 5000,
"tickets_per_unit": 1
}
],
"tickets_count": 2,
"amounts": {
"tickets": 10000,
"discount": 0,
"service_fee": 1000,
"service_fee_payer": "customer",
"charged": 11000,
"organizer_net": 10000
},
"coupon": null,
"promoter_id": null,
"utm": {
"source": "instagram",
"medium": "bio",
"campaign": "lancamento"
}
}
],
"pagination": {
"limit": 50,
"has_more": true,
"next_cursor": "4a088077-e3c4-4fff-a87a-2fa706b36664"
}
}/events/{id}/orders/{orderId}permissão: leituraBuscar pedido
Um pedido com todos os ingressos emitidos.
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
| orderId * | caminho | Id do pedido. |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269/orders/7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": {
"id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"number": "7D2C1B0A",
"event_id": "89646811269",
"status": "paid",
"channel": "online",
"payment_method": "pix",
"installments": null,
"created_at": "2026-10-18T15:18:40.000Z",
"paid_at": "2026-10-18T15:20:03.000Z",
"cancelled_at": null,
"buyer": {
"name": "Maria Souza",
"email": "maria@email.com",
"phone": "11999990000"
},
"items": [
{
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"quantity": 2,
"unit_price": 5000,
"tickets_per_unit": 1
}
],
"tickets_count": 2,
"amounts": {
"tickets": 10000,
"discount": 0,
"service_fee": 1000,
"service_fee_payer": "customer",
"charged": 11000,
"organizer_net": 10000
},
"coupon": null,
"promoter_id": null,
"utm": {
"source": "instagram",
"medium": "bio",
"campaign": "lancamento"
},
"tickets": [
{
"id": "0f3e2d1c-4b5a-6978-8a9b-0c1d2e3f4a5b",
"code": "IJ7K2M9QX4",
"event_id": "89646811269",
"order_id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"status": "valid",
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"half_price": false,
"spot": null,
"holder_name": "Maria Souza",
"buyer_email": "maria@email.com",
"used_at": null,
"used_by": null,
"created_at": "2026-10-18T15:20:04.000Z"
}
]
}
}/events/{id}/ticketspermissão: leituraListar ingressos
Ingressos emitidos (participantes) do evento, na ordem de emissão.
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
| status | query | Situação do ingresso.valid | used | cancelled |
| query | E-mail do comprador. | |
| sector_id | query | Só ingressos deste setor. |
| order_id | query | Só ingressos deste pedido. |
| limit | query | Itens por página, de 1 a 200. Padrão: 50. |
| cursor | query | Valor de pagination.next_cursor da página anterior. |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269/tickets" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": [
{
"id": "0f3e2d1c-4b5a-6978-8a9b-0c1d2e3f4a5b",
"code": "IJ7K2M9QX4",
"event_id": "89646811269",
"order_id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"status": "valid",
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"half_price": false,
"spot": null,
"holder_name": "Maria Souza",
"buyer_email": "maria@email.com",
"used_at": null,
"used_by": null,
"created_at": "2026-10-18T15:20:04.000Z"
}
],
"pagination": {
"limit": 50,
"has_more": true,
"next_cursor": "4a088077-e3c4-4fff-a87a-2fa706b36664"
}
}/events/{id}/tickets/{code}permissão: leituraBuscar ingresso
Um ingresso pelo código (o mesmo conteúdo do QR code).
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
| code * | caminho | Código do ingresso. |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269/tickets/IJ7K2M9QX4" \ -H "Authorization: Bearer SEU_TOKEN"
Resposta 200
{
"data": {
"id": "0f3e2d1c-4b5a-6978-8a9b-0c1d2e3f4a5b",
"code": "IJ7K2M9QX4",
"event_id": "89646811269",
"order_id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"status": "valid",
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"half_price": false,
"spot": null,
"holder_name": "Maria Souza",
"buyer_email": "maria@email.com",
"used_at": null,
"used_by": null,
"created_at": "2026-10-18T15:20:04.000Z"
}
}/events/{id}/tickets/{code}/check-inpermissão: check-inFazer check-in
Valida o ingresso na entrada (catraca, totem, app próprio). Mesma regra da portaria do IngressoJá: libera uma única vez; leitura repetida volta "used". Sempre responde 200 quando o ingresso foi lido: o resultado está em data.result (ok, used ou invalid).
| Parâmetro | Onde | Descrição |
|---|---|---|
| id * | caminho | Código do evento (o número do link: ingressoja.com/eventos/89646811269). |
| code * | caminho | Código do ingresso lido no QR code. |
| session_id | corpo | Festival: o dia da entrada (id em sessions). O passaporte entra uma vez por dia. |
Requisição
curl "https://api.ingressoja.com/v1/events/89646811269/tickets/IJ7K2M9QX4/check-in" \
-H "Authorization: Bearer SEU_TOKEN" \
-X POST -H "Content-Type: application/json" -d '{}'Resposta 200
{
"data": {
"result": "ok",
"message": "Entrada liberada.",
"code": "IJ7K2M9QX4",
"sector": "Pista",
"half_price": false,
"holder_name": "Maria Souza",
"used_at": null,
"used_by": null
}
}Webhooks
Cadastre o endereço https do seu sistema em Integrações › API › Webhooks e escolha os avisos. Cada aviso chega como POST com JSON. Responda com qualquer status 2xx em até 10 segundos; se o seu sistema estiver fora, tentamos de novo depois de 1, 5, 30, 120 e 360 minutos.
| Aviso | Quando | Em data |
|---|---|---|
| order.paid | O pagamento foi aprovado e os ingressos foram emitidos (site, app ou bilheteria). | event + order (com tickets) |
| order.refunded | O pagamento foi devolvido ou contestado; os ingressos válidos foram cancelados. | event + order (com tickets) |
| order.cancelled | Uma venda paga foi cancelada (por exemplo, na bilheteria). | event + order (com tickets) |
| ticket.checked_in | Entrada liberada na portaria, no painel ou pela API. | event + ticket + check_in { at, by, session_id } |
| event.updated | O evento foi salvo, ou as vendas foram pausadas ou retomadas. | event (com sectors) |
Cabeçalhos: X-IngressoJa-Event (o tipo), X-IngressoJa-Delivery (id único da entrega — use para ignorar repetidos) e X-IngressoJa-Signature.
{
"id": "5b9c1e2f-3a4d-4e6f-8a7b-9c0d1e2f3a4b",
"type": "order.paid",
"created_at": "2026-10-18T15:20:04.000Z",
"data": {
"event": {
"id": "89646811269",
"internal_id": "6a1f2c9e-0b5d-4e2a-9c41-3f8e7d2b1a90",
"name": "Danilo & Davi",
"subtitle": null,
"category": "Show",
"kind": "single",
"status": "published",
"sales_paused": false,
"starts_at": "2026-11-06T02:00:00.000Z",
"ends_at": null,
"gates_open_at": "2026-11-05T23:00:00.000Z",
"sales_start_at": null,
"timezone": "America/Sao_Paulo",
"age_rating": "18",
"image_url": "https://ingressoja.com/s3/ingressoja/public/eventos/danilo-e-davi.webp",
"url": "https://ingressoja.com/eventos/89646811269",
"venue": {
"name": "Villa Country",
"city": "São Paulo",
"state": "SP",
"address": {
"street": "Av. Francisco Matarazzo",
"number": "774",
"district": "Barra Funda",
"zip_code": "05001100"
}
},
"sessions": [],
"created_at": "2026-10-17T23:51:10.000Z",
"updated_at": "2026-10-18T14:02:44.000Z"
},
"order": {
"id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"number": "7D2C1B0A",
"event_id": "89646811269",
"status": "paid",
"channel": "online",
"payment_method": "pix",
"installments": null,
"created_at": "2026-10-18T15:18:40.000Z",
"paid_at": "2026-10-18T15:20:03.000Z",
"cancelled_at": null,
"buyer": {
"name": "Maria Souza",
"email": "maria@email.com",
"phone": "11999990000"
},
"items": [
{
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"quantity": 2,
"unit_price": 5000,
"tickets_per_unit": 1
}
],
"tickets_count": 2,
"amounts": {
"tickets": 10000,
"discount": 0,
"service_fee": 1000,
"service_fee_payer": "customer",
"charged": 11000,
"organizer_net": 10000
},
"coupon": null,
"promoter_id": null,
"utm": {
"source": "instagram",
"medium": "bio",
"campaign": "lancamento"
},
"tickets": [
{
"id": "0f3e2d1c-4b5a-6978-8a9b-0c1d2e3f4a5b",
"code": "IJ7K2M9QX4",
"event_id": "89646811269",
"order_id": "7d2c1b0a-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
"status": "valid",
"sector_id": "b2f0c0aa-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"sector": "Pista",
"half_price": false,
"spot": null,
"holder_name": "Maria Souza",
"buyer_email": "maria@email.com",
"used_at": null,
"used_by": null,
"created_at": "2026-10-18T15:20:04.000Z"
}
]
}
}
}Conferir a assinatura
Ao criar o webhook, o painel mostra um segredo (whsec_...). Cada aviso traz X-IngressoJa-Signature: t=1760800804,v1=5f2a…, em que v1 é o HMAC-SHA256, em hexadecimal, de <t>.<corpo> com o segredo. Confira sempre antes de confiar no conteúdo, use o corpo exatamente como chegou e recuse avisos com t de mais de 5 minutos.
Node.js
const crypto = require('crypto')
// rawBody = o corpo exatamente como chegou (texto, antes do JSON.parse)
function webhookValido(headerAssinatura, rawBody, segredo) {
const partes = Object.fromEntries(headerAssinatura.split(',').map((p) => p.split('=')))
const esperado = crypto.createHmac('sha256', segredo).update(partes.t + '.' + rawBody).digest('hex')
const recente = Math.abs(Date.now() / 1000 - Number(partes.t)) < 300 // até 5 minutos
return recente && crypto.timingSafeEqual(Buffer.from(partes.v1), Buffer.from(esperado))
}PHP
<?php
$corpo = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_INGRESSOJA_SIGNATURE']), $partes);
$esperado = hash_hmac('sha256', $partes['t'] . '.' . $corpo, $segredo);
$valido = hash_equals($esperado, $partes['v1']) && abs(time() - (int) $partes['t']) < 300;Python
import hmac, hashlib, time
def webhook_valido(header, corpo: bytes, segredo: str) -> bool:
partes = dict(p.split("=", 1) for p in header.split(","))
esperado = hmac.new(segredo.encode(), partes["t"].encode() + b"." + corpo, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, partes["v1"]) and abs(time.time() - int(partes["t"])) < 300Boas práticas
- Prefira os webhooks a consultar a API a cada poucos segundos: o aviso chega na hora e não gasta o seu limite.
- Os avisos podem chegar repetidos ou fora de ordem: use o id da entrega e o status do pedido para não processar duas vezes.
- Catraca: faça o check-in pela API (
POST …/check-in). A regra é a mesma da portaria do IngressoJá — um ingresso só entra uma vez, mesmo que seja lido em dois aparelhos ao mesmo tempo. - Os dados de compradores são pessoais (LGPD): guarde só o necessário e proteja o token e o segredo como senhas.
- Dúvidas ou um recurso que falta: contato@ingressoja.com.