Read API

The read path is completely separate from the write path: a separate rate limit pool, a separate cache and independent scaling. Ingest traffic never slowing down your dashboard is a direct result of this separation.

Authentication

Read endpoints accept two kinds of credentials:

Form Where it is used
Authorization: Bearer <access-token> A user signed in to the dashboard
X-API-KEY: ebrd_pub_… From the browser, from embedded components

A publishable key is accepted only from origins on its allowed domain list. A request from anywhere else gets 403; even if the key leaks, it cannot be used on another site.

Endpoints

Endpoint Returns
GET /api/v1/projects/{id}/summary Precomputed summary (event counts, open Issues, monitor status)
GET /api/v1/projects/{id}/issues Issue list (cursor pagination)
GET /api/v1/projects/{id}/issues/counts Counts by status
GET /api/v1/issues/{id} Issue details
GET /api/v1/issues/{id}/events Raw events linked to the Issue
GET /api/v1/issues/{id}/breakdown Breakdown by release/environment/server
GET /api/v1/projects/{id}/events Log search (full text + filters)
GET /api/v1/projects/{id}/events/histogram Time series (time_bucket)
GET /api/v1/projects/{id}/usage Quota usage
GET /api/v1/projects/{id}/releases Events, errors, new errors and regressions per release
GET /api/v1/projects/{id}/releases/details?release= The errors a release introduced and brought back, and the previous release
GET /api/v1/projects/{id}/dashboards Custom dashboards and their chart definitions
GET /api/v1/projects/{id}/dashboards/{dashboardId}/widgets/{widgetId}/data Data of a saved chart
POST /api/v1/projects/{id}/widget-data Data of an unsaved chart
GET /api/v1/monitors/{id}/uptime Uptime percentage and daily breakdown
GET /api/v1/monitors/{id}/ssl-status Certificate status and days left
GET /api/v1/monitors/{id}/domain-status Domain expiry date and registrar
GET /api/v1/projects/{id}/stream Live event stream (SSE)
GET /status/{slug} Public status page (no authentication)

Cursor pagination

List endpoints have no offset. Pagination uses the base64url-encoded (timestamp, id) pair of the last row:

curl "https://api.errorbird.com/api/v1/projects/<id>/issues?limit=50" -H "X-API-KEY: ebrd_pub_…"
# { "items": [...], "nextCursor": "MjAyNi0wOC0xOVQyMTowMDowMFo…" }

curl "https://api.errorbird.com/api/v1/projects/<id>/issues?limit=50&cursor=MjAyNi0w…"

When nextCursor is null, the list is complete. The reason there is no offset is correctness, not performance: if a new event arrives while you are reading page 2, offset-based pagination skips a record or shows it twice.

Live stream (SSE)

const source = new EventSource(
  'https://api.errorbird.com/api/v1/projects/<id>/stream?apiKey=ebrd_pub_…',
)

source.addEventListener('event', (message) => {
  console.log(JSON.parse(message.data))
})

Because EventSource cannot send custom headers, the key is taken from the query string. This path accepts publishable keys only — if a secret key were accepted in the query string, a key with write access would end up in server logs and browser history.

Releases

/releases answers "what did this deploy break?". All your events need is the release field (release in Serilog/CLEF bodies, init({ release }) in the browser SDK); events without the tag are not listed.

[
  {
    "release": "[email protected]",
    "firstSeen": "2026-10-11T09:02:14Z",
    "lastSeen": "2026-10-11T10:27:40Z",
    "eventCount": 454,
    "errorCount": 194,
    "newIssueCount": 2,
    "regressionCount": 1
  }
]

The dashboard's "errors/hour" comparison is calculated from this data: the number of error events divided by the hours between the release's first and last event. The raw count of a release that has been live for a short time cannot be compared with one that has been live for days.

Dashboards

The Dashboards page in the dashboard lets you build your own charts from a project's logs, issues and monitors. Chart data is not stored; it is computed for the selected range (1 hour – 90 days) every time it is opened. The same endpoints can be read with a publishable key, so you can draw the charts in your own panel. Creating and changing dashboards requires a dashboard session (member role); at most 20 dashboards per project and 24 charts per dashboard.

Chart (kind) What it shows Fields
LogVolume Log count over time; optional breakdown (top 5 values + "others") query, minLevel, environment, release, groupBy
LogCount Log count in the range and in the previous range of equal length query, minLevel, environment, release
LogTopValues The 10 most frequent values of a field the same filters + required groupBy
NewIssues Issues seen for the first time, over time minLevel
MonitorResponseTime Average and p95 response time of successful checks monitorId
MonitorUptime Share of successful checks and the previous range monitorId

groupBy: level, environment, release, server, template (message template) or meta:Field — a property in the log metadata, e.g. meta:TenantId. query uses the same syntax as log search.

# Data of a saved chart (range: 15m, 6h, 24h, 7d, 90d…; day buckets follow timeZone)
curl "https://api.errorbird.com/api/v1/projects/<project-id>/dashboards/<dashboard-id>/widgets/<widget-id>/data?range=7d&timeZone=Europe/London" \
  -H "X-API-KEY: ebrd_pub_…"

# Without saving: send the definition, get its data
curl -X POST https://api.errorbird.com/api/v1/projects/<project-id>/widget-data \
  -H "X-API-KEY: ebrd_pub_…" -H "Content-Type: application/json" \
  -d '{ "range": "24h", "widget": { "id": "x", "title": "Errors by tenant",
        "kind": "LogTopValues", "minLevel": "Error", "groupBy": "meta:TenantId" } }'
{
  "kind": "LogVolume", "unit": "count", "bucketSeconds": 10800,
  "from": "2026-10-04T12:00:00Z", "to": "2026-10-11T12:00:00Z",
  "series": [ { "name": "Error", "points": [ { "time": "2026-10-04T12:00:00Z", "value": 0 }, … ] },
              { "name": "__other__", "points": [ … ] } ],
  "rows": [], "value": 1810, "previousValue": null
}

Caching and latency

/summary, /uptime and /ssl-status are cached in Redis and backed by TimescaleDB continuous aggregates. Measured values: p99 18 ms from the cache, p99 189 ms with an empty cache (a project with 120,503 events).

With an empty cache, concurrent requests for the same key share a single computation (single flight); N requests do not trigger N separate queries.

Rate limits

The read pool allows 600 requests per minute (per key + origin). Beyond that, the response is 429. This counter is independent of the write pool.

Public endpoints (status page, plan catalog, SSO discovery) are limited to 120 requests per minute per IP.

Multi-tenant isolation

A request for a resource of another organization/workspace returns 404, not 403. A 403 confirms that the resource exists, which is an information leak on its own.