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

  1. 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).
  2. Copie o token na hora: ele aparece uma única vez. Se perder, revogue e crie outro.
  3. 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 id de 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). Quando pagination.has_more for 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.

400invalid_status / invalid_date / invalid_sessionParâmetro com valor inválido.
401missing_token / invalid_tokenToken ausente, errado ou revogado.
403insufficient_scopeO token não tem a permissão da rota (leitura ou check-in).
404event_not_found / order_not_found / ticket_not_foundNão existe, ou não é da sua conta.
429rate_limitedMais de 120 pedidos por minuto com o mesmo token.

Endpoints

Base: https://api.ingressoja.com/v1

GET/eventspermissão: leitura

Listar eventos

Eventos da sua conta, do mais próximo para o mais distante. Para os setores de cada evento, use “Buscar evento”.

ParâmetroOndeDescrição
statusquerySituação do evento.published | upcoming | draft | cancelled
fromquerySó eventos que começam a partir desta data (AAAA-MM-DD ou ISO 8601).
limitqueryItens por página, de 1 a 200. Padrão: 50.
cursorqueryValor 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"
  }
}
GET/events/{id}permissão: leitura

Buscar evento

Um evento com setores, preços (centavos), vendidos e disponíveis. Festivais trazem os dias em sessions.

ParâmetroOndeDescrição
id *caminhoCó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
      }
    ]
  }
}
GET/events/{id}/orderspermissão: leitura

Listar pedidos

Pedidos do evento, do mais recente para o mais antigo, com comprador, itens, valores e origem (UTM).

ParâmetroOndeDescrição
id *caminhoCódigo do evento (o número do link: ingressoja.com/eventos/89646811269).
statusquerySituação do pedido.paid | pending | cancelled | refunded | expired
emailqueryE-mail do comprador.
fromqueryPedidos feitos a partir desta data.
toqueryPedidos feitos até esta data.
limitqueryItens por página, de 1 a 200. Padrão: 50.
cursorqueryValor 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"
  }
}
GET/events/{id}/orders/{orderId}permissão: leitura

Buscar pedido

Um pedido com todos os ingressos emitidos.

ParâmetroOndeDescrição
id *caminhoCódigo do evento (o número do link: ingressoja.com/eventos/89646811269).
orderId *caminhoId 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"
      }
    ]
  }
}
GET/events/{id}/ticketspermissão: leitura

Listar ingressos

Ingressos emitidos (participantes) do evento, na ordem de emissão.

ParâmetroOndeDescrição
id *caminhoCódigo do evento (o número do link: ingressoja.com/eventos/89646811269).
statusquerySituação do ingresso.valid | used | cancelled
emailqueryE-mail do comprador.
sector_idquerySó ingressos deste setor.
order_idquerySó ingressos deste pedido.
limitqueryItens por página, de 1 a 200. Padrão: 50.
cursorqueryValor 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"
  }
}
GET/events/{id}/tickets/{code}permissão: leitura

Buscar ingresso

Um ingresso pelo código (o mesmo conteúdo do QR code).

ParâmetroOndeDescrição
id *caminhoCódigo do evento (o número do link: ingressoja.com/eventos/89646811269).
code *caminhoCó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"
  }
}
POST/events/{id}/tickets/{code}/check-inpermissão: check-in

Fazer 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âmetroOndeDescrição
id *caminhoCódigo do evento (o número do link: ingressoja.com/eventos/89646811269).
code *caminhoCódigo do ingresso lido no QR code.
session_idcorpoFestival: 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.

AvisoQuandoEm data
order.paidO pagamento foi aprovado e os ingressos foram emitidos (site, app ou bilheteria).event + order (com tickets)
order.refundedO pagamento foi devolvido ou contestado; os ingressos válidos foram cancelados.event + order (com tickets)
order.cancelledUma venda paga foi cancelada (por exemplo, na bilheteria).event + order (com tickets)
ticket.checked_inEntrada liberada na portaria, no painel ou pela API.event + ticket + check_in { at, by, session_id }
event.updatedO 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"])) < 300

Boas 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.