Pular para o conteúdo principal
CONTRATO Quatro perguntas, respondidas por escrito: o que consideramos mudança que quebra, quanto tempo uma versão fica no ar, como avisamos uma depreciação e o que assumimos como compromisso. O que já mudou de fato está no changelog. Cada item desta página é um compromisso que cumprimos, e a última seção diz como a versão é escolhida e quanto tempo ela convive com a seguinte.

Onde vive a versão

A versão do contrato HTTP está no caminho: /v1. Não existe cabeçalho de versão, e a sua integração não escolhe versão por requisição. Enquanto a URL começar com /v1, valem as regras desta página.

A versão do envelope do evento

O caminho versiona a API. O corpo do webhook versiona a si mesmo: todo evento sai com schema_version, hoje 3, logo depois do id. Ele descreve a forma do envelope, não o conteúdo da verificação. Esse número não sobe por adição compatível. Campo novo no corpo, módulo novo em check_details e valor novo num enum de saída continuam com schema_version: 3, porque a lista logo acima já obriga a sua integração a tolerar essas três coisas. Ele sobe quando um campo muda de tipo ou de significado, e isso, pela lista de baixo, também exige /v2: os dois marcadores andam juntos de propósito, e é por isso que você nunca vai precisar decidir qual dos dois seguir. Na prática, para quem integra: leia o campo, registre o valor no seu log e trate um número maior que o esperado como sinal de que existe uma versão nova de caminho para migrar. Não recuse o evento por causa dele: enquanto o número for 3, o corpo é o mesmo que você já sabe ler.

Como entregamos: pelo menos uma vez

Isto não é uma promessa nova, é o registro por escrito do que a plataforma sempre fez. Você vai receber o mesmo evento mais de uma vez em algum momento, e isso não é defeito: é o preço de nunca perder um desfecho. O que garantimos é a entrega, não a unicidade dela, e é por isso que o id do evento é estável, para servir de chave de deduplicação no seu lado.
  • → Entregamos pelo menos uma vez. O mesmo evento pode chegar mais de uma vez, e o seu endpoint precisa ser idempotente.
  • → Deduplique pelo campo id do evento (evt_…). Ele é estável por verificação e por tipo de evento, então toda retentativa do mesmo evento repete o mesmo id.
  • → Reemissão manual (decisão revista no painel, e também a re-decisão automática quando uma análise continua e muda o resultado) chega com id NOVO de propósito: é evento novo, e você deve tratar como upsert pelo verification_id.
  • → O replay self-service é o oposto, e por desenho: ele reenvia a MESMA entrega que falhou, byte a byte, com o MESMO id do evento original. É o mesmo evento chegando de novo, não um evento novo: a dedup por id continua valendo e nada é processado duas vezes.
  • → Uma entrega só é considerada aceita quando o seu endpoint responde 2xx. Timeout, erro de rede ou 5xx contam como falha e entram na retentativa.
  • → São até 3 tentativas, com espera crescente entre elas (cerca de 15 minutos do primeiro disparo à última). Depois disso o resgate é o replay, que você dispara quando o seu sistema voltar.
  • → Resposta 4xx DE CONTRATO (400, 401, 403, 404, 405, 410 e 422) é lida como recusa definitiva daquele destino e não gera novas tentativas: o corpo não vai mudar se o problema é o pedido. Corrija e use o replay.
  • → As duas exceções entre os 4xx são as que um receptor sob carga devolve: 408 e 429 contam como falha TRANSITÓRIA e entram na retentativa normalmente. Se você limita taxa no seu endpoint, prefira 429 a 403.
  • → Resposta 3xx NÃO é entrega e NÃO é seguida: nós fazemos um POST na URL cadastrada e paramos ali. Redirecionar o destino (inclusive de http para https, ou de com barra final para sem) faz o evento parar de chegar, e a tentativa fica registrada com o status 301 ou 302 para você ver em GET /v1/webhook-events. Quem conserta isso é o cadastro da URL, não o retry.
  • → A entrega repetida é assinada NA HORA do envio, com timestamp novo sobre o mesmo corpo, então a sua validação de assinatura e a sua janela anti-replay continuam passando.
  • → O corpo do evento carrega schema_version, a versão da forma do envelope. Campo novo não muda esse número; mudança de tipo ou de significado muda, e nesse caso já existiria uma versão nova de caminho, salvo Correção de segurança, que entra em /v1 e sobe o número junto.
A consequência prática é uma só: o seu endpoint precisa ser idempotente. Guarde o id já processado e ignore a repetição, ou trate todo evento como um upsert pelo verification_id. Quem processa webhook sem isso credita duas vezes, aprova duas vezes, ou dispara dois e-mails, no primeiro dia em que a rede engasgar.

O que é adição compatível

Estas mudanças entram em /v1 a qualquer momento, sem aviso prévio. A sua integração é obrigada a tolerá-las. Na prática isso significa: não quebre em campo desconhecido no JSON, não trate valor de enum desconhecido como erro fatal, não valide a resposta contra um esquema fechado, e não dependa da ordem das propriedades de um objeto.
  • + Endpoint novo, ou módulo novo no catálogo.
  • + Campo novo na resposta ou no corpo do webhook.
  • + Parâmetro opcional novo no request.
  • + Tipo de evento novo no webhook.
  • + Valor novo em um enum de SAÍDA (um status novo, um módulo novo em check_details, um motivo novo).
  • + Item novo dentro de um array já existente.
  • + Reordenação das propriedades de um objeto JSON.
  • + Mudança de tamanho ou de formato de uma string opaca (id, token, prefixo de chave).

O que é mudança que quebra

Estas nunca entram em /v1. Se um dia forem necessárias, elas exigem um caminho novo, /v2, e a versão antiga continua respondendo do jeito que sempre respondeu enquanto estiver no ar.
  • ! Remover ou renomear endpoint, parâmetro, header, campo de resposta ou módulo.
  • ! Mudar o tipo de um campo.
  • ! Exigir campo novo no request, ou criar validação que recusa um request antes válido.
  • ! Mudar o código de status HTTP de um caso já documentado.
  • ! Mudar o SIGNIFICADO de um campo mantendo o nome dele.
  • ! Remover um valor aceito em um enum de ENTRADA.
  • ! Mudar a exigência de autenticação de uma rota.
Duas exceções, pelo mesmo motivo que o mercado inteiro as abre: mudança em respostas 5xx e em 404 de recurso inexistente não conta como quebra, porque são justamente os casos em que o contrato não estava sendo cumprido.

Quanto tempo uma versão fica no ar

Aviso de 90 dias antes de uma versão nova entrar no ar, e 12 meses de convivência entre a nova e a antiga contados a partir do lançamento. Passado esse prazo, a versão antiga responde 410, e não um erro genérico: você recebe uma resposta que diz exatamente o que aconteceu.

Como avisamos uma depreciação

Depreciação é anúncio com data de saída. Ela aparece no changelog classificada como Depreciação, com o dia em que o comportamento antigo sai do ar, e no feed /docs/changelog.json no campo sunset_on daquele item, para o seu monitoramento enxergar sem depender de alguém ler esta página. O painel também traz o aviso, mas o registro que vale é o changelog: o painel é lido por uma pessoa, e integração não é gente.

A exceção de segurança

Correção de vulnerabilidade entra em /v1 na hora, sem janela de aviso, mesmo que altere comportamento observável. Ela é registrada no changelog como Correção logo em seguida. Essa exceção existe para a promessa desta página não virar algema no meio de um incidente: entre cumprir o prazo e fechar um buraco que expõe dado de cliente, a gente fecha o buraco.

O que assumimos

  • ✓ Mudança que quebra nunca entra em /v1. Ela exige um caminho novo, /v2.
  • ✓ Antes de /v2 entrar no ar, o aviso sai aqui no changelog com 90 dias de antecedência.
  • ✓ /v1 e /v2 convivem por 12 meses contados do dia em que /v2 entra no ar. Depois disso, /v1 responde 410.
  • ✓ Depreciação é anunciada nesta página com a data de saída, nunca só por e-mail.
  • ✓ Correção de vulnerabilidade entra em /v1 na hora, sem janela de aviso, e é registrada aqui como Correção logo em seguida.
  • ✓ Toda entrada deste changelog só entra com a prova da data conferida no nosso repositório. Esta página publica o que mudou, não o mapa do nosso código.

Como a versão é escolhida

Uma regra só, pensada para o seu código não mudar de comportamento sem você mudar a URL.
  • - A versão é escolhida pelo caminho da URL, nunca por cabeçalho: a mesma URL devolve sempre a mesma forma de contrato, e um cabeçalho esquecido nunca muda a resposta que você recebe.
  • - Existe uma versão de caminho no ar por vez, sem versão nomeada por mês nem canal de preview: o que está em /v1 é o contrato inteiro, e o changelog registra cada mudança dele com a data.
  • - Quando uma versão nova de caminho entrar no ar, a anterior convive com ela por 12 meses, com o aviso publicado 90 dias antes.

Onde isso aparece no contrato

A cláusula 2.4 dos Termos de Uso fixa 30 dias de antecedência para mudança que altere de forma relevante o comportamento observável da API, anunciada neste changelog público e por aviso no painel, e diz que mudança que quebra integração existente não entra em /v1. São 30 dias porque é o mesmo prazo que os Termos já usam para alteração de preço de módulo e para o plano gratuito. Os 90 dias desta página são um prazo maior, e valem para o caso mais pesado de todos: colocar uma versão nova no ar.