Skip to main content
4 min read

title: "Chart Annotations API" description: "Create deploy / release / campaign annotations that overlay on every Zenovay timeseries chart, and feed F8 conversion incident triage."

Chart Annotations API

Customer-created annotations (deploys, releases, campaigns, incidents, custom) that overlay onto every timeseries chart in the Zenovay dashboard. Also consumed by the conversion incident triage as "suspect changes" within ±2h of an incident's start time.

Auth: this endpoint accepts your dashboard session cookie. For CI integrations and automation, use the Zenovay CLI which handles authentication via your account login. External zv_* API keys are not accepted on this endpoint today; the CLI is the canonical way to create annotations from a deploy pipeline.

Plan limits: Free = 10 annotations / month. Pro+ = unlimited.

Dedup: a same-type annotation within 5 minutes of an existing one is rejected with 409 Conflict. This prevents misconfigured CI from flooding the timeline.

Create an annotation

POST /api/annotations
Content-Type: application/json
Cookie: zenovay-session=<your-session-cookie>xxxxxxxxxxxxxxxxxxxxx

{
  "websiteId": "11111111-2222-3333-4444-555555555555",
  "type": "deploy",
  "message": "Ship checkout v2.5",
  "occurredAt": "2026-04-30T14:00:00Z",
  "metadata": { "sha": "a1b2c3d", "branch": "main" }
}

Fields

FieldTypeRequiredNotes
websiteIdUUIDYesThe website (Zenovay project) to annotate.
typeenumYesOne of deploy, release, campaign, incident, custom.
messagestringYes1–500 chars. Shown on hover and in the legend.
occurredAtISO 8601NoDefaults to server-side now() if omitted.
metadataobjectNoFree-form JSON for extra context (commit SHA, campaign URL, etc.).

Response

{
  "success": true,
  "data": {
    "annotation": {
      "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
      "website_id": "11111111-2222-3333-4444-555555555555",
      "team_id": "...",
      "type": "deploy",
      "message": "Ship checkout v2.5",
      "occurred_at": "2026-04-30T14:00:00Z",
      "created_by": "...",
      "metadata_json": { "sha": "a1b2c3d", "branch": "main" },
      "created_at": "2026-04-30T14:00:01Z"
    }
  }
}

List annotations

GET /api/annotations?websiteId=<uuid>&from=<iso>&to=<iso>
Cookie: zenovay-session=<your-session-cookie>

from and to are optional. Returns up to 500 annotations within the window, newest first.

Delete an annotation

DELETE /api/annotations/<annotation-id>
Cookie: zenovay-session=<your-session-cookie>

Returns { deleted: true } on success. Soft-delete is not supported in v1 — deletes are permanent.

Common patterns

Create a deploy marker from a CI pipeline

curl -X POST https://api.zenovay.com/api/annotations \
  -H "Authorization: Bearer $ZENOVAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"websiteId\": \"$WEBSITE_ID\",
    \"type\": \"deploy\",
    \"message\": \"Deploy $GIT_BRANCH @ $GIT_SHA\",
    \"metadata\": { \"sha\": \"$GIT_SHA\", \"branch\": \"$GIT_BRANCH\" }
  }"

From the Zenovay CLI

The Zenovay CLI is the recommended way to create annotations from a CI pipeline — it handles authentication automatically via the OAuth device-flow login.

zenovay annotation create --type=deploy --message="release v2.5"

The full set of flags:

FlagRequiredDefaultNotes
--typeYesOne of deploy, release, campaign, incident, custom.
--messageYes1–500 chars.
--occurred-atNonowISO 8601 timestamp.
--site-idNoconfigured siteUUID of the website.
--jsonNoEmit a single NDJSON envelope to stdout for CI scripting.

See the CLI integration page for the full command reference and a sample GitHub Actions step.

Where annotations appear

  • Every timeseries chart in the dashboard (vertical reference line
    • colored chip in the floating legend).
  • Conversion incident triage — incidents within ±2h of an annotation auto-list it as a "suspect change".
  • Public dashboards — annotations are not shown on public dashboards. Deploy and release messages are intended for the team operating the site, not for visitors.

Errors

StatusCodeMeaning
400VALIDATION_ERRORMissing or invalid required field.
402(none)Free-tier monthly limit reached. Upgrade to Pro+ for unlimited.
403(none)API key has no access to the target website.
404(none)Website not found.
409(none)Same-type annotation exists within 5 min of occurredAt.
Was this page helpful?