> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unifokal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Política de versão

> O que a UNIFOKAL considera mudança que quebra, quanto tempo uma versão da API fica no ar, como avisamos uma depreciação e o que assumimos como compromisso.

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](https://docs.unifokal.com/changelog.md).

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 `4`, 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: 4`, 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 `4`, 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.

| Se a /v2 entrasse no ar em | Então |
| - | - |
| 2026-10-03 | o aviso já estaria publicado no changelog, 90 dias antes. |
| 2027-01-01 | a `/v2` entra no ar e a `/v1` continua funcionando igual. |
| 2028-01-01 | a `/v1` sai do ar e passa a responder `410`. |

## Como avisamos uma depreciação

Depreciação é anúncio com **data de saída**. Ela aparece no [changelog](https://docs.unifokal.com/changelog.md) classificada como Depreciação, com o dia em que o comportamento antigo sai do ar, e no feed [`/docs/changelog.json`](https://unifokal.com/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](https://unifokal.com/termos) 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.