Spoar

Annotations

Dated labels on a project's time series for releases, posts, content updates and incidents, so a change in the numbers can be read next to what happened.

An annotation marks a date, or a range of dates, on a project's charts: a release, a post, a content update, an incident or any other event worth seeing next to the traffic. It is a label for the reader of the numbers. Nothing is tracked, and visitors never see it.

The data model

FieldTypeNotes
idstringann_ plus a UUID, set by the API
projectstringThe project it belongs to; every route is scoped to it
titlestring1 to 120 characters
datetimestampWhen it happened, in UTC
endDatetimestamp or nullThe end of a range; never before date
kindrelease, post, content, incident or otherother when not given
notestring or nullUp to 2,000 characters
urlstring or nullAn http:// or https:// URL of up to 2,048 characters
createdAt, updatedAttimestampSet by the API

date and endDate take a calendar date such as 2026-10-01, read as the start of that day in UTC, or an ISO 8601 timestamp with an offset such as 2026-10-01T09:30:00+02:00. Answers always carry UTC timestamps. Annotations live in the annotations table (migration 0031) and are removed with their project.

Routes

MethodPathAccessDoes
GET/v2/projects/:project/annotationsprojectThe annotations that overlap the range, oldest first, paged
POST/v2/projects/:project/annotationsadminAdds one
PATCH/v2/projects/:project/annotations/:annotationadminChanges the fields sent; null clears endDate, note or url
DELETE/v2/projects/:project/annotations/:annotationadminDeletes one
  • Reading follows the project: anyone for a public project, and a member or token that lists it for a private one, which answers 404 to anyone else. Writing needs an owner, an admin who lists the project, or an admin token that lists it.
  • The list takes the same range as every read: from and to, or period (24h, 7d, 30d, 90d, 12mo, all; default 30d). An annotation with an endDate is listed when any part of it falls in the range. limit (1 to 100, default 20) and cursor page it.
  • An endDate before date, on create or after a change, answers 400 VALIDATION_FAILED with /endDate in details.fields. An empty PATCH body is also VALIDATION_FAILED. An id that belongs to another project is 404 NOT_FOUND.
curl https://api.example.com/v2/projects/example.com/annotations \
  -H "authorization: Bearer $RA_ADMIN_TOKEN" \
  -H "content-type: application/json" \
  -d '{"title":"v2.0 released","date":"2026-10-01","kind":"release","url":"https://example.com/changelog"}'

From TypeScript, admin.annotations in /admin calls the same routes.

On this page