A maioria dos monitores entrega um diff da página e deixa a interpretação com você. A BriefPanel resolve a página nos itens que se repetem nela — um anúncio, uma moeda, uma vaga, um plano — e registra cada mudança como uma atualização tipada: qual campo mudou, de quanto para quanto, e o quanto isso importa.
Esta API é o lado de leitura desse histórico. Todo endpoint é um GET, devolve JSON e pagina do
mesmo jeito.
URL base
https://actions.briefpanel.com/v1
Autenticação
Envie uma chave pessoal de API como token Bearer:
Authorization: Bearer YOUR_BRIEFPANEL_API_KEY
Crie uma chave em Configurações → API e integrações no app (https://app.briefpanel.com/connect-agent).
As chaves começam com bp_mcp_ e a mesma chave vale para o servidor MCP — uma
credencial para as duas superfícies.
Tokens de acesso OAuth (bp_oat_) não são aceitos aqui. Eles são vinculados ao público (audience)
do recurso MCP, então autenticam apenas chamadas MCP.
Uma chave ausente ou inválida devolve 401 com o cabeçalho WWW-Authenticate.
Início rápido
Liste o que você monitora. Se vierem linhas, sua chave está funcionando:
curl https://actions.briefpanel.com/v1/sources \
-H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"
Depois leia o que mudou. É este o endpoint que a maioria das integrações consulta:
curl "https://actions.briefpanel.com/v1/updates?importance=material&limit=50" \
-H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"
Uma resposta reduzida — o formato completo está no documento OpenAPI:
{
"data": [
{
"id": "j57e...",
"at": 1750000000000,
"updateType": "modified",
"importance": "material",
"field": "price",
"valueChange": {
"type": "number",
"previous": 149.9,
"current": 129.9,
"unit": "BRL"
},
"entry": { "id": "k17c...", "title": "Plano Pro", "kind": "pricing plan" },
"source": { "id": "m92a...", "url": "https://example.com/pricing" }
}
],
"pagination": { "nextCursor": "eyJ...", "hasMore": true }
}
Endpoints
| Endpoint | Parâmetros de query | Devolve |
|---|---|---|
GET /v1/sources |
limit, cursor |
As páginas que você monitora, das mais recentes para as mais antigas, cada uma com seu status derivado e os tipos de item aprendidos para aquela página. |
GET /v1/sources/{id}/entries |
limit, cursor |
Os itens atualmente resolvidos em uma página, ordenados pela atualização mais recente. Rascunhos de onboarding em andamento ficam de fora. |
GET /v1/updates |
since, importance, limit, cursor |
Todas as mudanças item a item em todas as suas fontes, das mais recentes para as mais antigas. É o feed para consultar. |
GET /v1/entries/{id}/updates |
field, importance, limit, cursor |
O fluxo completo de eventos de um item. Filtre por field para o histórico de um único campo — a leitura por trás de um gráfico de preço. |
GET /v1/entries/{id}/changes |
limit, cursor |
Um cartão por coleta que mudou este item: contagens de diff, a variação de preço derivada e ponteiros para a evidência capturada. |
GET /v1/changes/{id}/snapshot |
state, format |
O estado capturado da página por trás de uma mudança. Devolve bytes, não o envelope JSON. |
Um id que pertence a outra conta devolve 404, não 403 — a API não confirma a existência de um
id que ela não vai servir.
Paginação
Toda coleção aceita limit e cursor e responde com um objeto pagination:
{ "pagination": { "nextCursor": "eyJ...", "hasMore": true } }
Passe nextCursor de volta como cursor para pegar a próxima página, e siga até hasMore ser
false.
Trate hasMore como o único sinal de fim da coleção. Uma página pode voltar vazia, ou menor que o
seu limit, e ainda haver mais para ler — parar em uma página curta trunca sua sincronização em
silêncio.
Consultando o feed
GET /v1/updates vem das mudanças mais recentes para as mais antigas. Leia o at do item mais
novo e devolva esse valor como since na próxima consulta para receber só o que mudou desde então:
curl "https://actions.briefpanel.com/v1/updates?since=1750000000000" \
-H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"
since aceita milissegundos desde a época (o formato que at devolve) ou um instante ISO-8601.
importance aceita critical, material ou minor.
Cada item carrega o entry e o source de origem embutidos, então uma atualização já é acionável
sem uma segunda chamada.
Webhooks de saída
Se você não quiser consultar o feed, adicione um endereço HTTPS público controlado pelo seu
sistema em Configurações → API e integrações → Webhooks de saída. Esse endereço não é uma
rota da API BriefPanel: o BriefPanel envia um POST HTTP a ele sempre que registra um novo evento
de item content.update.
O corpo reutiliza os campos canônicos de atualização de GET /v1/updates, incluindo
updateType, importance, os contextos de fonte e item e o par field mais valueChange
tipado. O envelope do webhook também carrega o id estável do evento e occurredAt.
Cada requisição inclui:
| Cabeçalho | Significado |
|---|---|
BriefPanel-Event-Id |
Id estável de content_updates, igual em todas as tentativas. Use-o como chave de idempotência. |
BriefPanel-Timestamp |
Horário da tentativa de entrega em segundos Unix. Use-o para rejeitar requisições assinadas antigas. |
BriefPanel-Signature |
v1=<HMAC-SHA256 em hexadecimal> de <event-id>.<timestamp>.<corpo-bruto>, usando o segredo mostrado uma única vez ao criar o endpoint. |
Uma resposta 2xx conclui a entrega. Timeouts, falhas de rede/DNS, 408, 425, 429 e respostas
5xx recebem no máximo cinco tentativas, com intervalos exponenciais de 1, 2, 4 e 8 minutos.
Outras respostas, inclusive redirects, falham imediatamente. A entrega é pelo menos uma vez; por
isso, o receptor deve deduplicar pelo id do evento. Uma falha no receptor nunca desfaz o ingest nem
bloqueia outro endpoint. O app mostra o último status e a quantidade de tentativas; registros de
entrega concluídos expiram após 30 dias.
Tipos de item
Cada item carrega um kind — pricing plan, job posting, cryptocurrency. Os nomes são
aprendidos por fonte, então compare apenas dentro de uma mesma fonte; o vocabulário de cada página
é publicado como entryKinds na fonte, junto com hasPrice para você saber quando a ausência de
um preço é significativa.
entryKinds só aparece depois que a fonte foi analisada.
Saúde da fonte
GET /v1/sources devolve um status derivado:
status |
Significado |
|---|---|
active |
Sendo verificada normalmente. |
autoPaused |
Pausada após falhas seguidas de coleta. |
creditPaused |
Pausada por falta de créditos. |
disabled |
Desligada por você. |
lastFetchOutcome, lastFetchErrorReason, consecutiveFetchFailures e nextFetchTime trazem o
detalhe por trás disso.
Evidência
GET /v1/changes/{id}/snapshot serve o estado bruto da página de onde a mudança veio, para você
mostrar a origem de um valor em vez de pedir que confiem nele.
Snapshots são deduplicados entre contas e não têm dono próprio, então são endereçados pela mudança
a que pertencem, e não por um id próprio. Pegue o changeId de um cartão da linha do tempo e
verifique hasCurrentSnapshot / hasPreviousSnapshot antes de pedir um estado.
state—current(padrão) ouprevious.previousdevolve404na primeira mudança, que não tem estado anterior.format—markdown(padrão),htmlouscreenshot.screenshotresponde com um302para uma URL de imagem assinada e de vida curta.
Erros
Falhas devolvem um objeto de erro:
{ "error": { "code": "not_found", "message": "No source with that id." } }
Trate pelo code em vez do status HTTP — o conjunto é fixo, cada código responde com exatamente
um status, e nem o conjunto nem essa correspondência mudam sob você. A message é escrita para
humanos e pode ser reescrita; não faça parsing dela.
code |
HTTP | Quando |
|---|---|---|
invalid_request |
400 | Parâmetro inválido ou fora do intervalo. |
unauthorized |
401 | Chave ausente, malformada ou revogada. |
forbidden |
403 | A chave não tem o escopo que o endpoint exige. |
not_found |
404 | Id inexistente, incluindo um que pertence a outra conta. |
method_not_allowed |
405 | Um verbo de escrita nesta API somente leitura. |
rate_limited |
429 | Requisições demais para esta chave. |
internal |
500 | Um erro do nosso lado. |
A API é somente leitura: GET e o preflight OPTIONS são os únicos métodos servidos. Qualquer
outro — POST, PUT, PATCH, DELETE — responde 405 method_not_allowed com o cabeçalho
Allow, no mesmo envelope de erro.
Limites de uso
As leituras são limitadas por chave de API, em uma janela fixa de 300 requisições por minuto.
Toda resposta contada pelo limite carrega a cota atual, então dá para ritmar o cliente em vez de descobrir o teto batendo nele:
| Cabeçalho | Significado |
|---|---|
X-RateLimit-Limit |
Requisições permitidas por janela. |
X-RateLimit-Remaining |
Requisições restantes nesta janela, já descontando a que você fez. |
X-RateLimit-Reset |
Segundos até a janela reiniciar — um intervalo, não um timestamp Unix. |
Esses cabeçalhos acompanham uma resposta contada, o que inclui os erros que a requisição só
alcançou depois de chegar a um handler: um 400 ou 404 traz a cota igual a um 200. Uma
requisição recusada por chave inválida (401/403) é barrada antes da contagem, então não traz
nenhuma.
Trate a ausência deles como desconhecido, nunca como zero. Eles também são omitidos se o nosso limitador estiver momentaneamente indisponível — nesse caso a requisição é servida sem ser contada.
Acima do limite você recebe 429 com o cabeçalho Retry-After, em segundos e sempre no mínimo um
— respeite-o em vez de tentar de novo imediatamente.
OpenAPI
A especificação completa é servida como documento OpenAPI 3.0 vivo:
https://actions.briefpanel.com/v1/openapi.json
Importe no Postman, aponte um gerador de SDK para ela ou entregue a URL para um agente. Ela descreve cada endpoint, o esquema de autenticação, o contrato de paginação e todos os formatos de resposta.
É servida sem autenticação de propósito — uma ferramenta precisa conseguir ler a descrição da API antes de ter uma chave.