evobits

evobits · especificação de integração · ingestão de incidentes

Contrato de ingestão de incidentes

Como um sistema que já sabe abrir e fechar os próprios incidentes propaga esse ciclo de vida para uma página de status do evobits, sem duplicar o cadastro em dois lugares.

Para
Sistemas que originam incidente (status page interna, ferramenta de on-call, script)
Endpoint
/api/ingest/incidente
Métodos
POST · PATCH · DELETE
Base
https://<slug>.status.evobits.com.br

Copia esta especificação inteira em Markdown, para colar no ChatGPT, no Claude, no Gemini ou no assistente que vocês usam.

Exemplo de prompt
Preciso propagar o ciclo de vida de incidente do nosso sistema para o evobits,
seguindo a especificação que vou colar abaixo.

Nossa stack: (descreva aqui: linguagem, framework, cliente HTTP).

Leia a especificação inteira e:
1. gere o código de POST na abertura, PATCH em toda atualização e DELETE se o
   incidente for excluído (não só resolvido);
2. mande refOrigem estável (o id do incidente no NOSSO sistema) e atualizadoEm
   a cada chamada;
3. trate 404 (token inválido) e 503 (retry) como o documento pede;
4. escreva os testes do checklist de aceite.

<COLE AQUI O TEXTO COPIADO PELO BOTÃO "COPIAR PARA IA">

01Por que este contrato existe

Uma página de status do evobits também tem incidentes cadastrados no próprio painel administrativo, mas alguns clientes já têm um sistema que origina o incidente sozinho: a ferramenta de on-call de um produto integrado, por exemplo. Nesses casos o cadastro continua acontecendo no sistema de origem; este endpoint só recebe o ESPELHO desse ciclo de vida, para a mesma página de status mostrar os dois tipos de incidente juntos, na mesma linha do tempo.

Incidente criado por aqui carrega origem = "lite" internamente (nome herdado da primeira integração deste tipo) e nunca é editável pelo painel administrativo: só quem mandou pode atualizar ou excluir, pelo mesmo refOrigem usado na criação.

02Autenticação

Todo pedido leva um token de ingestão no cabeçalho. O token é criado no painel administrativo (Integrações → Tokens de ingestão), pertence a UMA página do tenant, e todo incidente criado com ele nasce nessa página.

X-Evobits-Token: <token>

X-NW-Status-Token funciona como alias PERMANENTE do mesmo cabeçalho (mande um ou outro, nunca os dois com valores diferentes), é o nome que a primeira integração deste tipo já usa em produção, e não vai mudar.

Token ausente, vazio, incorreto, revogado, ou cujo tenant está suspenso: sempre 404, exatamente igual a um caminho que não existe. Nunca 401, nunca 403 -- é para não anunciar que a rota existe para quem não tem o token certo.

03Criar (POST)

POST /api/ingest/incidente
X-Evobits-Token: <token>
Content-Type: application/json
Corpo
CampoObrigatórioO que é
refOrigemsimId estável do incidente NO SEU sistema (1 a 200 caracteres). É a chave de idempotência
titulosim2 a 200 caracteres
corposimTexto do primeiro update da timeline, 2 a 5000 caracteres
estadosiminvestigating, identified, monitoring ou resolved
inicioEmnãoISO 8601; padrão é o instante do POST. Não pode estar no futuro nem ser anterior a 2 anos atrás
resolvidoEmnãoISO 8601 ou null; só importa quando estado é resolved (padrão: o instante do POST)
atualizadoEmnãoISO 8601, o carimbo da linha no SEU sistema. Ver a guarda de ordem na seção 04, vale mandar sempre
curl -X POST https://minha-pagina.status.evobits.com.br/api/ingest/incidente \
  -H "X-Evobits-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "refOrigem": "inc-48213",
    "titulo": "Latência elevada na API de pagamentos",
    "corpo": "Estamos investigando um aumento de latência.",
    "estado": "investigating",
    "atualizadoEm": "2026-09-23T14:02:00Z"
  }'

201 na criação, com o incidente e o primeiro item da timeline:

{
  "incidente": { "id": "…", "titulo": "…", "estado": "investigating", "…": "…" },
  "timeline": [ { "id": "…", "corpo": "…", "estado": "investigating", "criadoEm": "…" } ]
}

Idempotente por refOrigem. Reenviar o MESMO refOrigem (o caso normal depois de um timeout de rede do seu lado) não cria um segundo incidente: responde 200 com o incidente como está, sem alterar nada. Para mudar algo depois de criado, use PATCH.

04Atualizar (PATCH)

PATCH /api/ingest/incidente/<refOrigem>
X-Evobits-Token: <token>
Content-Type: application/json

Todo campo é opcional (mande ao menos um): titulo, corpo, estado, resolvidoEm, atualizadoEm, mesmas regras de forma do POST. Um update novo entra na timeline só quando estado muda OU corpo é diferente do último update; um PATCH que só confirma o que já estava não deixa uma linha repetida no histórico.

curl -X PATCH https://minha-pagina.status.evobits.com.br/api/ingest/incidente/inc-48213 \
  -H "X-Evobits-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "estado": "resolved",
    "corpo": "Latência normalizada. Causa: pool de conexões saturado.",
    "resolvidoEm": "2026-09-23T14:41:12Z",
    "atualizadoEm": "2026-09-23T14:41:12Z"
  }'

Guarda de ordem por atualizadoEm. O seu sistema manda o ESTADO INTEIRO a cada propagação, não só o que mudou, isso evita perder mudança, mas não protege contra a ORDEM de chegada numa rede que reenvia e pode entregar fora de ordem. Por isso: se o atualizadoEm recebido for mais antigo ou igual ao já gravado, o PATCH é ignorado em silêncio (200, incidente devolvido sem mudar nada). Omitir o campo desativa a guarda, é o caminho de compatibilidade, mas mandar sempre é o recomendado.

200 com o incidente atualizado e o novo item de timeline, se um foi criado:

{ "incidente": { "…": "…" }, "update": { "…": "…" } }

404 incidente_nao_encontrado quando o refOrigem não existe para o token usado (inclusive se pertence a outro token/tenant). 400 titulo_vazio ou corpo_vazio se o campo mandado, depois de aparado, fica em branco.

05Excluir (DELETE)

DELETE /api/ingest/incidente/<refOrigem>
X-Evobits-Token: <token>

Para quando o incidente foi cadastrado por engano no sistema de origem, não para o fluxo normal de resolução (isso é um PATCH com estado: "resolved").

Idempotente. Excluir o que já não existe também responde 204 -- é o caso normal de um reenvio depois de timeout, não uma exceção.

06Erros e retentativa

SituaçãoResposta
Token ausente, errado, revogado ou tenant suspenso404, corpo igual ao de uma rota inexistente
Título ou corpo vazio depois de aparado400 titulo_vazio / corpo_vazio
Data de início inválida (futuro, antiga demais, ou depois da resolução)400, ver o campo error no corpo
Banco sem conexão livre no momento503 banco_indisponivel, com Retry-After

Um 503 é sempre seguro de reenviar: nada foi gravado. Espere o Retry-After (em segundos) antes de tentar de novo. Um timeout de rede no POST também é seguro de reenviar, com o MESMO refOrigem, a idempotência da seção 03 garante que não vira um segundo incidente.

07Como saber que está entregue

  1. 01POST sem token responde 404; com token errado ou revogado, também 404.
  2. 02POST cria o incidente e devolve 201 com a timeline.
  3. 03Reenviar o MESMO refOrigem não duplica: 200, sem alterar nada.
  4. 04PATCH muda estado e/ou corpo, e o item novo aparece na timeline só quando algo de fato mudou.
  5. 05PATCH com atualizadoEm mais antigo que o gravado é ignorado em silêncio (200, sem mudar nada).
  6. 06DELETE remove; repetir o DELETE continua respondendo 204.
  7. 07Um refOrigem de outro token/tenant nunca aparece nem é alterável pelo seu (404).