API de leitura

O endpoint de webhook é público e só de escrita: é assim que as suas apps enviam alertas ao Zenhook. Para ler os alertas de volta (criar uma CLI, sincronizar com outra ferramenta, criar um painel), use a API autenticada com um token Bearer.

Autenticação

Todos os endpoints de leitura exigem um token Bearer. Os tokens são limitados a um único par(utilizador, espaço de trabalho): o acesso aos canais do utilizador (incluindo os canais privados de que faz parte) é herdado automaticamente.

Gerar um token

No painel: Definições → Tokens de API → Novo token. O token completo aparece uma única vez, na criação: copie-o de imediato. O Zenhook guarda apenas um hash SHA-256, por isso um token perdido não pode ser recuperado (revogue-o e crie outro).

Formato do token
zhk_<48 hex chars>
# example: zhk_a1b2c3d4e5f6...

Enviar o token

bash
curl https://zenhook.dev/api/channels \
  -H "Authorization: Bearer zhk_..."

Listar os canais

Devolve os canais a que o utilizador do token tem acesso (todos os canais públicos e qualquer canal privado de que é membro). Cada canal traz um campo _count.alerts com o número pessoal de mensagens não lidas.

GEThttps://zenhook.dev/api/channels

Respostas

200 OK
json
[
  {
    "id": "clx_chan_1",
    "name": "production-errors",
    "slug": "production-errors",
    "icon": "🔴",
    "isPrivate": false,
    "webhookToken": "abc123...",
    "_count": { "alerts": 3 }
  }
]

Listar os alertas de um canal

Paginado, do mais recente para o mais antigo. Cada alerta traz um booleano isRead calculado para o utilizador que faz o pedido: marcar um alerta como lido só afeta o seu próprio estado.

GEThttps://zenhook.dev/api/channels/{id ou slug}/alerts

Use o slug do canal em vez do id e leia um canal pelo nome numa só chamada, sem ter de procurar nada antes:

bash
curl https://zenhook.dev/api/channels/deploys/alerts \
  -H "Authorization: Bearer zhk_..."

Parâmetros de consulta

cursorstring
ID de alerta devolvido como nextCursor na página anterior. Omita-o na primeira página.
limitnumber
1-100. Predefinição: 50.
levelenum
Filtrar por nível: info, success, warning, error.
afterstring
ID de alerta. Devolve os alertas estritamente mais recentes; usado para polling.

Respostas

200 OK
json
{
  "alerts": [
    {
      "id": "clx_alert_1",
      "channelId": "clx_chan_1",
      "title": "Build Failed",
      "level": "ERROR",
      "emoji": "🔴",
      "message": "npm install timed out after 300s",
      "fields": [{ "label": "Branch", "value": "main" }],
      "linkUrl": "https://github.com/org/repo/actions/runs/123",
      "isRead": false,
      "createdAt": "2026-04-27T14:32:11.000Z"
    }
  ],
  "nextCursor": "clx_alert_42",
  "hasMore": true
}

Marcar como lido

O estado de leitura é de cada utilizador. Marcar um alerta como lido grava uma linha apenas para o utilizador do token: os contadores de não lidos dos outros membros do espaço de trabalho não mudam.

PATCHhttps://zenhook.dev/api/alerts/{id}
bash
curl -X PATCH https://zenhook.dev/api/alerts/clx_alert_1 \
  -H "Authorization: Bearer zhk_..." \
  -H "Content-Type: application/json" \
  -d '{ "isRead": true }'

Marcar todos os alertas como lidos

POSThttps://zenhook.dev/api/alerts/mark-all-read

O corpo é opcional. Envie { "channelId": "..." } para limitar a um canal; omita-o para marcar como lidos todos os canais acessíveis. Idempotente: repetir não tem efeito.

Obter um único alerta

GEThttps://zenhook.dev/api/alerts/{id}

Devolve a mesma estrutura de alerta do endpoint de listagem, mais o name / slug do canal.

Erros

401 Unauthorized: token Bearer em falta ou inválido, ou o utilizador do token já não é membro do espaço de trabalho. O corpo da resposta diz qual é o caso, não precisa de adivinhar:

json
{
  "error": "Unauthorized",
  "reason": "token_env_var_unset",
  "message": "The client sent the literal string \"undefined\", so the variable holding it is unset. Node does not read a .env file on its own: run node --env-file=.env your-script.mjs, or export the variable before running it.",
  "docs": "https://zenhook.dev/docs/api/read"
}
  • no_credentials: nenhum cabeçalho Authorization.
  • malformed_authorization_header: o cabeçalho não é Bearer <token>.
  • token_env_var_unset: o seu cliente enviou um token vazio ou a string undefined. A variável que guarda o token não está definida.
  • invalid_token_format: o token não ézhk_ + 48 caracteres hexadecimais.
  • unknown_token: o token foi revogado, ou ficou cortado ao ser copiado.
  • not_a_workspace_member: o token é válido, mas o utilizador saiu do espaço de trabalho.

404 Not Found: o recurso não existe ou o utilizador do token não lhe tem acesso (por exemplo, um canal privado de que não é membro). Os dois casos são iguais de propósito, para que quem tem um token não consiga enumerar os canais privados.

429 Too Many Requests: limite de pedidos atingido. Aguarde e tente novamente.