A DL Pay Acquirer entrega uma solução completa de venda de ingressos sobre a conta unificada do vendedor. Um evento possui um ou mais ingressos, opcionalmente com desconto por cupons. O comprador cria um checkout pelo fluxo público, paga por PIX ou cartão de crédito e recebe os ingressos por e-mail. Métricas pré-agregadas acompanham as vendas em tempo real conforme os checkouts mudam de situação. O sistema tem duas superfícies:
  • Superfície autenticada (/event/seller/{account_id}/...) — usada pelo vendedor para gerenciar eventos, ingressos, cupons, checkouts e métricas. Requer um Bearer JWT ou uma chave de API.
  • Superfície pública (/event/event/{event_id}/...) — usada pela vitrine. Sem autenticação. Serve para renderizar a página do evento e conduzir o comprador pelo checkout.
Este guia segue o caminho do macaco: a sequência mais curta de chamadas que leva o vendedor de uma conta em branco até um ingresso pago na caixa de entrada do comprador.

Tipos e nomenclaturas de evento

Todo evento é criado com dois rótulos ortogonais. type controla onde o evento acontece e qual bloco de endereço é obrigatório:
typeSignificadoBloco de endereço obrigatório
IN_PERSONLocal físico.Bloco address (logradouro, cidade, CEP, …)
ONLINEEvento virtual.Bloco digital_address (platform, url opcional)
nomenclature é como a vitrine chama cada “ingresso” na interface — não altera comportamento, apenas a terminologia:
nomenclatureRótulo na vitrine (pt-BR)Uso típico
TICKETINGIngressoEntrada paga para um show, festival ou aula.
REGISTRATIONInscriçãoInscrições para curso, congresso ou competição.
CONTRIBUTIONContribuiçãoDoações ou pagamentos com valor sugerido.
subject e category são escolhidos a partir de listas predefinidas e servem apenas para descoberta e exibição.

Fluxo de compra do cliente em resumo

Etapa 1 — Criar o evento

O vendedor chama o endpoint autenticado vinculado à sua conta unificada. A plataforma resolve {account_id} para uma conta unificada e anexa o evento a ela (e ao vendedor subjacente). Campos obrigatórios:
  • name, description, image_url (banner — faça upload primeiro pela ação upload_logo, máximo 2 MB).
  • type (IN_PERSON ou ONLINE), subject, category, nomenclature.
  • starts_at, ends_at (ISO 8601, com fuso horário).
  • address se IN_PERSON, caso contrário digital_address.
Opcionais comumente usados:
  • public — padrão true. Defina como false durante a edição; a vitrine resolve o evento via endpoint de contexto público independentemente, mas você normalmente controla o compartilhamento pela sua própria interface.
  • max_installments — teto rígido de parcelas para pagamentos com cartão. Padrão "12".
  • max_installments_no_tax — parcelas em que o vendedor absorve juros. "0" significa que o juro recai sempre sobre o comprador e o PIX também recebe o acréscimo. Padrão "0".
1

Suba a imagem de capa

POST /event/seller/{account_id}/events/upload_logo/ (multipart, campo file). Retorna { "url": "..." } para usar como image_url.
2

Crie o evento

POST no endpoint de eventos. A resposta inclui um campo link — a URL da vitrine pública configurada para o vendedor.
curl -X POST "https://api.dlpay.cloud/event/seller/$ACCOUNT_ID/events/" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Festival Sunset 2026",
    "description": "Edição de aniversário.",
    "type": "IN_PERSON",
    "image_url": "https://cdn.dlpay.cloud/events/sunset.jpg",
    "subject": "27",
    "category": "39",
    "nomenclature": "TICKETING",
    "max_installments": "12",
    "max_installments_no_tax": "3",
    "starts_at": "2026-08-12T22:00:00Z",
    "ends_at": "2026-08-13T06:00:00Z",
    "address": {
      "name": "Arena Sunset",
      "display_map_widget": true,
      "neighborhood": "Centro",
      "city": "São Paulo",
      "state": "SP",
      "postal_code": "01001-000",
      "country_code": "BR",
      "street": "Av. Paulista",
      "number": "1000",
      "complement": ""
    }
  }'

Etapa 2 — Criar ingressos

Cada ingresso é um item vendável: um nível de preço, uma cota de estoque, uma janela de vendas opcional e uma lista opcional de perguntas que o comprador deve responder no checkout. Campos principais:
  • name (até 45 caracteres), description, amount em centavos de BRL. Ingressos gratuitos são simplesmente amount: 0 — o checkout é automaticamente promovido para a situação FREE e o e-mail de confirmação é disparado sem passar pelo processador.
  • quantity — estoque total para esse tipo de ingresso. Padrão 1000. O ingresso expõe a propriedade quantity_available, que subtrai checkouts ativos em PENDING, PAID e FREE e expira automaticamente os PENDING com mais de 16 minutos a cada leitura.
  • sales_period_typeALWAYS (padrão) ou PERIOD. Quando PERIOD, defina sales_starts_at e sales_ends_at.
  • questions — lista de objetos { id, prompt, type, values?, validation_regex? }. O type da pergunta é um de LIST, RADIO, STRING, INTEGER, DATE, EMAIL, PHONE, CPF. LIST / RADIO exigem values. STRING pode carregar um validation_regex. Os ids das perguntas são normalizados em slug e deduplicados no servidor; um id vazio recebe como padrão o slug do prompt.
O campo se chama quantity, não max_quantity. Enviar max_quantity é silenciosamente ignorado e o ingresso usará o padrão de 1000 vagas.

Etapa 3 — Cupons de desconto opcionais

Cupons aplicam valor fixo ou percentual sobre o total do checkout inteiro (não por ingresso). Campos:
  • name — rótulo de exibição.
  • code — o que o comprador digita. É colocado em maiúsculas e tem espaços removidos no servidor. Deve ser único dentro do evento e não pode conter espaços.
  • typeFIXED (valor em centavos de BRL) ou PERCENTAGE (valor de 1 a 100).
  • value — deve ser > 0. Para PERCENTAGE, limitado a 100.
O desconto é calculado na criação do checkout sobre a soma de todos os valores de ingresso do pedido. Cupons FIXED são limitados para que o total nunca fique negativo. Se o total resultante ficar abaixo de um centavo, o checkout é movido para FREE imediatamente.

Etapa 4 — Publicar

public tem valor padrão true na criação. A vitrine pública resolve um evento puramente por seu UUID via endpoint de contexto público — não existe endpoint público de listagem. Duas regras de visibilidade a lembrar:
  • O contexto público omite o vendedor, a conta e a url do evento digital. A url da reunião só é revelada após o checkout chegar em PAID / FREE.
  • O quantity_available retornado pelo contexto público é calculado ao vivo e dispara como efeito colateral a expiração automática de 16 minutos para checkouts pendentes.
Compartilhe o campo link retornado pelos endpoints de criação/consulta de evento com seus compradores. Ele aponta para a vitrine pública padrão configurada para o vendedor, mas a API pública é totalmente utilizável a partir de qualquer frontend.

Etapa 5 — Fluxo do cliente

1

Carregue o contexto do evento

GET /event/event/{event_id}/ retorna nome, descrição, banner, endereço, configuração de parcelas e a lista de ingressos vendáveis com quantity_available.
2

(Opcional) Valide um código de cupom

POST /event/event/{event_id}/checkout/validate-coupon/ com {"code": "SUNSET10"} retorna { valid: true, coupon: {...} } ou { valid: false }. Use para dar feedback imediato ao comprador antes que ele finalize o formulário.
3

Crie o checkout

POST /event/event/{event_id}/checkout/ com customer, tickets (uma entrada por ingresso individual; repita o mesmo ticket id para comprar vários do mesmo tipo), question_answers de cada ingresso e coupon_code opcional. Retorna { id, status, total, original_total, discount_amount, ... }.O estoque é reservado neste momento: o checkout entra na contagem PENDING de cada ingresso solicitado. Permanece pagável por 20 minutos.
4

Obtenha detalhes e plano de pagamento

GET /event/event/{event_id}/checkout/{checkout_id}/ (a ação payment_details no mesmo recurso) retorna o resumo do checkout mais um bloco payment_plan: allowPix, allowCreditCard, maxInstallments, maxInstallmentsWithoutInterest. A leitura deste endpoint também move automaticamente para EXPIRED qualquer checkout que tenha passado dos 20 minutos.
5

Envie o pagamento

POST /event/event/{event_id}/checkout/{checkout_id}/pay/ com o método de pagamento do comprador (cartão ou PIX). O endpoint reutiliza o cliente capturado na criação, cria uma transação na conta do vendedor, anexa uma referência DL-EVC-<event_id>-<checkout_id> e retorna o payment_info (QR PIX + copia-e-cola, URL de desafio 3DS etc.). Checkouts gratuitos (total < 1) pulam essa etapa inteira.
6

Aguarde o processador

Quando a transação subjacente é liquidada, o pipeline regular de webhooks atualiza a situação do checkout para PAID. A transição dispara:
  • Atualizações atômicas de métricas nas tabelas de vendas por data, por evento e por hora.
  • A rotina de envio do e-mail de confirmação, que gera o PDF do ingresso e o envia por e-mail.
7

Entregue os ingressos

GET /event/event/{event_id}/checkout/{checkout_id}/tickets/ faz streaming do mesmo PDF sob demanda. Enquanto is_paid for falso, o endpoint renderiza uma página HTML de “não pago” no lugar.

Etapa 6 — Monitorar e validar

Com o evento em venda, o vendedor o gerencia pelos endpoints autenticados em /event/seller/{account_id}/events/{events_pk}/.
AçãoEndpointNotas
Listar pedidosGET .../checkouts/Filtra por status, busca por customer.name / customer.email. Retorna linhas com ticket_count, coupon, total.
Consultar pedidoGET .../checkouts/{id}/Retorna detalhes completos, incluindo cada ingresso do checkout com answers interpretadas e carimbo used_at, além de transaction_id.
Exportar CSV / ExcelGET .../checkouts/report/Uma linha por ingresso; cada resposta de pergunta aparece em uma coluna [P] <prompt>. Defina Accept como text/csv, o mime do Excel ou text/plain.
Relatório financeiroGET .../checkouts/financial-report/Junta dados de transação unificada e recebíveis. Inclui MDR, valor líquido, total a receber e bandeira do cartão.
Validar um ingresso na entradaPOST .../checkouts/validate-ticket/ com {"ticketCheckoutId": "..."}Marca um ingresso do checkout como utilizado (define used_at). Recusa quando o checkout não está pago ou o ingresso já foi usado.
Reenviar confirmaçãoPOST .../checkouts/{id}/resend-email/ com {"email": "..."} (sobrescrita opcional)Exige is_paid. Refaz a geração do PDF e o envio do e-mail.

Métricas em tempo real

As transições de situação do checkout alimentam quatro tabelas pré-agregadas:
ModeloGranularidadeContador
Vendas por datadiasoma do total do checkout (centavos de BRL)
Ingressos por datadiaticket_count (quantidade de ingressos)
Ingressos por data e eventodia + eventoticket_count
Ingressos por data e horadia + horaticket_count
Cada atualização de métrica é invocada a partir da mudança de situação do checkout e usa incrementos atômicos para que transições concorrentes nunca percam contagem. Entrar em PAID / FREE incrementa; sair de PAID / FREE (por exemplo, um cancelamento manual ou estorno que move para CANCELED) decrementa. Outras transições não geram efeito. Leia os agregados pelos endpoints autenticados de métricas: Todos os quatro aceitam date_after / date_before e limitam a resposta aos últimos 90 dias. Como são gravados sincronicamente junto da mudança de situação do checkout, as leituras são consultas O(1) e não agregações sobre a tabela de pedidos.

Listagem administrativa de eventos

Para operadores da plataforma, GET /event/admin/events/ retorna todos os eventos de todas as contas, com dados de exibição do vendedor e da conta, anotados com tickets_sold (soma das vendas por evento). O endpoint exige permissão de superusuário — vendedores comuns recebem 403.

Exemplo ponta a ponta

O script abaixo cria um evento com um ingresso pago, exibe o link público e conduz um comprador pelo checkout até receber o payload do PIX.
Python
import requests

BASE = "https://api.dlpay.cloud"
TOKEN = "<jwt-do-vendedor-ou-chave-de-api>"
ACCOUNT_ID = "<uuid-da-conta-unificada>"

auth = {"Authorization": f"Bearer {TOKEN}"}

event = requests.post(
    f"{BASE}/event/seller/{ACCOUNT_ID}/events/",
    headers=auth,
    json={
        "name": "Workshop de Lançamento",
        "description": "Tarde prática.",
        "type": "ONLINE",
        "image_url": "https://cdn.dlpay.cloud/events/workshop.jpg",
        "subject": "24",
        "category": "35",
        "nomenclature": "REGISTRATION",
        "max_installments": "6",
        "max_installments_no_tax": "3",
        "starts_at": "2026-06-10T19:00:00-03:00",
        "ends_at": "2026-06-10T22:00:00-03:00",
        "digital_address": {"platform": "ZOOM", "url": "https://zoom.us/j/123"},
    },
).json()

ticket = requests.post(
    f"{BASE}/event/seller/{ACCOUNT_ID}/events/{event['id']}/tickets/",
    headers=auth,
    json={
        "name": "Inscrição Geral",
        "amount": 5000,
        "quantity": 50,
        "description": "Acesso ao workshop ao vivo.",
        "questions": [
            {"prompt": "Empresa", "type": "STRING"},
        ],
    },
).json()

print("Link da vitrine:", event["link"])

context = requests.get(f"{BASE}/event/event/{event['id']}/").json()
sellable = context["tickets"][0]

checkout = requests.post(
    f"{BASE}/event/event/{event['id']}/checkout/",
    json={
        "customer": {
            "name": "Maria Silva",
            "email": "maria@example.com",
            "phone_number": "11987654321",
            "country_code": "+55",
        },
        "tickets": [
            {
                "ticket": sellable["id"],
                "question_answers": [
                    {"question_id": "empresa", "answer": "Acme"},
                ],
            }
        ],
    },
).json()

pix = requests.post(
    f"{BASE}/event/event/{event['id']}/checkout/{checkout['id']}/pay/",
    json={"type": "pix"},
).json()

print("Mostre este PIX ao comprador:", pix)

Armadilhas

  • As situações do checkout são específicas do domínio. Use EXPIRED, FREE, PENDING, PAID, CANCELED. Estados genéricos de transação como CONFIRMED / REFUNDED não se aplicam ao checkout de evento — filtrar ou comparar com eles sempre retorna zero linhas.
  • É quantity, não max_quantity. O campo de estoque do ingresso é quantity. Não existe max_quantity e campos desconhecidos são descartados silenciosamente — seus ingressos ficarão com o padrão de 1000 vagas.
  • Reservas de estoque expiram em 16 minutos. O quantity_available expira automaticamente checkouts em PENDING com mais de 16 minutos a cada leitura, mas os próprios checkouts permanecem pagáveis por 20 minutos via is_payable. As duas janelas são intencionais — o comprador ainda consegue concluir o pagamento por alguns minutos depois que a vaga já foi tecnicamente liberada.
  • Ingressos gratuitos pulam o processador. Quando total < 1 (por exemplo, ingressos todos gratuitos ou um cupom de 100%), a criação muda a situação para FREE. Não chame pay/ nesses casos — retornará 400.
  • Os ids de pergunta são em slug. prompt: "Tamanho da camiseta" vira id: "tamanho-da-camiseta". Esse mesmo slug é o que você envia de volta em question_answers[].question_id.
  • A url digital é sensível. Ela nunca é retornada pelo contexto público do evento. Exponha apenas a donos autenticados ou a compradores depois que o checkout chegar em PAID / FREE.
  • Códigos de cupom são insensíveis a maiúsculas, mas armazenados em caixa alta. Um cupom code: "sunset10" é armazenado como SUNSET10; tanto a validação quanto a criação do checkout aplicam strip().upper() antes da busca.
  • As métricas são deltas com sinal, não snapshots. Mover manualmente um checkout pago de volta para PENDING fora do fluxo normal decrementará contadores e geralmente é um erro — deixe o pipeline do processador conduzir as transições.

Fluxo de transação

O que acontece depois que a chamada pay/ do checkout chega ao processador.

Webhooks e rotinas

Como o webhook do processador conduz o checkout até PAID e dispara o e-mail de confirmação.

Referência da API de eventos

Referência campo a campo para cada endpoint de evento.

Convenções

Valores em centavos, formato de erro, paginação e fusos horários.