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
| Field | Type | Required | Notes |
|---|---|---|---|
websiteId | UUID | Yes | The website (Zenovay project) to annotate. |
type | enum | Yes | One of deploy, release, campaign, incident, custom. |
message | string | Yes | 1–500 chars. Shown on hover and in the legend. |
occurredAt | ISO 8601 | No | Defaults to server-side now() if omitted. |
metadata | object | No | Free-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:
| Flag | Required | Default | Notes |
|---|---|---|---|
--type | Yes | — | One of deploy, release, campaign, incident, custom. |
--message | Yes | — | 1–500 chars. |
--occurred-at | No | now | ISO 8601 timestamp. |
--site-id | No | configured site | UUID of the website. |
--json | No | — | Emit 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
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Missing 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. |