All docs

REST API

Read the item-level change history of any page you monitor as JSON — typed before/after values, cursor pagination, Bearer auth, and a published OpenAPI 3.0 spec.

Most monitors hand you a page diff and leave the interpretation to you. BriefPanel resolves a page into the items that repeat on it — a listing, a coin, a job, a plan — and records each change as a typed update: which field moved, from what to what, and how much it matters.

This API is the read side of that history. Every endpoint is a GET, returns JSON, and paginates the same way.

Base URL

https://actions.briefpanel.com/v1

Authentication

Send a personal API key as a Bearer token:

Authorization: Bearer YOUR_BRIEFPANEL_API_KEY

Create a key under Settings → Connect your agent in the app (https://app.briefpanel.com/connect-agent). Keys start with bp_mcp_ and the same key works for the MCP server — one credential for both surfaces.

OAuth access tokens (bp_oat_) are not accepted here. They are audience-bound to the MCP resource, so they authenticate MCP calls only.

A missing or invalid key returns 401 with a WWW-Authenticate header.

Quick start

List what you monitor. If this returns rows, your key works:

curl https://actions.briefpanel.com/v1/sources \
  -H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"

Then read what changed. This is the endpoint most integrations poll:

curl "https://actions.briefpanel.com/v1/updates?importance=material&limit=50" \
  -H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"

A trimmed response — the full shape is in the OpenAPI document:

{
  "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 Query parameters Returns
GET /v1/sources limit, cursor The pages you monitor, newest first, each with its derived status and the entry kinds learned for that page.
GET /v1/sources/{id}/entries limit, cursor The items currently resolved on one page, most recently updated first. In-flight onboarding stubs are omitted.
GET /v1/updates since, importance, limit, cursor Every item-level change across all your sources, newest first. The feed to poll.
GET /v1/entries/{id}/updates field, importance, limit, cursor One entry's full event stream. Filter by field for a single field's history — the read behind a price chart.
GET /v1/entries/{id}/changes limit, cursor One card per fetch that changed this entry: diff churn counts, the derived price move, and pointers to the captured evidence.
GET /v1/changes/{id}/snapshot state, format The captured page state behind a change. Returns bytes, not the JSON envelope.

An id belonging to another account returns 404, not 403 — the API does not confirm that an id it will not serve exists.

Pagination

Every collection takes limit and cursor and answers with a pagination object:

{ "pagination": { "nextCursor": "eyJ...", "hasMore": true } }

Pass nextCursor back as cursor to get the next page, and keep going until hasMore is false.

Treat hasMore as the only end-of-collection signal. A page can come back empty, or shorter than your limit, while there is still more to read — stopping on a short page will silently truncate your sync.

Polling the feed

GET /v1/updates is ordered newest first. Read at off the newest item and pass it back as since on the next poll to get only what has moved since:

curl "https://actions.briefpanel.com/v1/updates?since=1750000000000" \
  -H "Authorization: Bearer YOUR_BRIEFPANEL_API_KEY"

since accepts epoch milliseconds (the form at returns) or an ISO-8601 instant. importance accepts critical, material, or minor.

Each item carries its parent entry and source inline, so an update is actionable without a second call.

Entry kinds

Each entry carries a kindpricing plan, job posting, cryptocurrency. The names are learned per source, so compare them only within one source; the vocabulary for a given page is published as entryKinds on that source, along with hasPrice so you know when a missing price is meaningful.

entryKinds is absent until a source has been analyzed.

Source health

GET /v1/sources returns a derived status:

status Meaning
active Being checked on schedule.
autoPaused Paused after repeated fetch failures.
creditPaused Paused for lack of credits.
disabled Switched off by you.

lastFetchOutcome, lastFetchErrorReason, consecutiveFetchFailures and nextFetchTime carry the detail behind it.

Evidence

GET /v1/changes/{id}/snapshot serves the raw page state a change was derived from, so you can show where a value came from rather than asking someone to trust it.

Snapshots are deduped across accounts and have no owner of their own, so they are addressed through the change they belong to rather than by their own id. Take changeId from a timeline card and check hasCurrentSnapshot / hasPreviousSnapshot before requesting a state.

  • statecurrent (default) or previous. previous returns 404 on a first change, which has no prior state.
  • formatmarkdown (default), html, or screenshot. screenshot answers with a 302 to a short-lived signed image URL.

Errors

Failures return an error object:

{ "error": { "code": "not_found", "message": "No source with that id." } }

Branch on code rather than on the HTTP status — the codes are a fixed set and will not change under you.

code HTTP When
unauthorized 401 Missing, malformed, or revoked key.
forbidden 403 The key lacks the scope this endpoint needs.
not_found 404 No such id, including one that belongs to another account.
invalid_request 400 An unparseable or out-of-range parameter.
rate_limited 429 Too many requests for this key.
internal 500 An error on our side.

Rate limits

Reads are limited per API key, in a fixed window of 300 requests per minute. Over the limit you get 429 with a Retry-After header in seconds — honor it rather than retrying immediately.

OpenAPI

The full specification is served as a live OpenAPI 3.0 document:

https://actions.briefpanel.com/v1/openapi.json

Import it into Postman, point an SDK generator at it, or hand the URL to an agent. It describes every endpoint, the auth scheme, the pagination contract, and the complete response schemas.

It is served unauthenticated on purpose — tooling has to be able to read an API's description before it holds a key.

Two ways in, one API key. Read the typed history of what changed on any page you monitor, or hand the same credential to an agent.

Get your API key