Vivere

HTTP API

Monitors, pages, sharing, teams, alert channels and pixels over HTTP, with keys you can limit by permission and page.

Everything you do in the dashboard, apart from your password, sign-in methods, billing and API keys, you can also do with the HTTP API. Create a key under API keys and send it as a bearer token. All endpoints are under https://vivere.dev/api/v1, take and return JSON, and see what your account sees in the dashboard, within what the key is allowed.

curl -H "Authorization: Bearer vv_…" https://vivere.dev/api/v1/monitors

The same key works for the MCP server, whose tools call these endpoints.

Key permissions

A key has full access, which covers everything below and anything the API learns to do later, or the permissions you choose for it, one per resource:

PermissionRead allowsWrite also allows
monitorsMonitors, their runs and run output, their status changes. Over MCP, check_in too, because a monitor's ping URL is enough to check in.Creating, changing, pausing, resuming and deleting monitors.
pagesPages, their public address, and on your own pages who they are shared with.Creating, renaming and deleting pages, making a page private, sharing with people and teams.
teamsTeams, their members and pages.Creating, renaming and deleting teams, adding and removing members.
channelsAlert channels. Secret settings are never returned.Creating, changing, deleting and testing channels.
pixelsTracking pixels and their loads.Creating and deleting pixels, setting and removing a pixel's image.
eventsStatus changes across your own monitors.(read only)

A key can also be limited to some pages, your own or ones shared with you. It then sees nothing on any other page, as if those monitors and pages did not exist, and it cannot create pages. Monitors it creates without naming a page go on the first page it has. A key can be given an expiry of 30, 90 or 365 days; after that it answers 401.

A key only ever narrows what its account can do: on a page shared with you to view, a full-access key still only views. Change a key's permissions and pages at any time under API keys; the change applies to its next request. GET /account says what a key may do, whatever it was granted.

Endpoints

Account

Method and pathNeedsWhat it does
GET /accountany keyYour account and plan, the plan's limits and what you use of them, and this key's permissions, all_pages, pages and expires_at.

Monitors

Method and pathNeedsWhat it does
GET /monitorsmonitors:readMonitors on every page the key can see, each with its page and access. ?page=<id> for one page.
POST /monitorsmonitors:writeCreate a monitor on your first page, or on "page": <id>. Returns it, including ping_url for heartbeats.
GET /monitors/{id}monitors:readOne monitor, with the channels it alerts.
PATCH /monitors/{id}monitors:writeChange a monitor. Only the fields sent change; the kind cannot.
DELETE /monitors/{id}monitors:writeDelete it and its history.
POST /monitors/{id}/pause, /resumemonitors:writePause or resume.
GET /monitors/{id}/runsmonitors:readA heartbeat monitor's newest runs (?limit=, default 50, up to 200) with outcome, times, exit code and any model, token counts, cost_usd and items they reported, plus cost_30d_usd and the monitor's cost_alert_usd.
GET /runs/{id}monitors:readOne run, with the output it sent as log, its address and user agent.
GET /monitors/{id}/eventsmonitors:readThe monitor's status changes, newest first (?limit=).
GET /pages/{page}/monitors/{slug}monitors:readOne monitor by page and slug, at any access, viewer included.

Pages and sharing

Method and pathNeedsWhat it does
GET /pagespages:readYour pages, then the pages shared with you, each with access: owner, editor or viewer.
POST /pagespages:writeCreate a page: {"title": "…", "slug": "…"}. The slug is made from the title when left out.
GET /pages/{page}pages:readOne page and its public url; on your own pages, its shares and team_shares.
PATCH /pages/{page}pages:writeChange its title or slug.
DELETE /pages/{page}pages:writeDelete an empty page that is not your first.
POST /pages/{page}/privatepages:writeTurn off Public on every monitor on it, which takes its status page down.
POST /pages/{page}/sharespages:writeShare with the account of a login: {"email": "…", "role": "viewer"} or "editor". Sending it again changes the role.
DELETE /pages/{page}/shares/{account}pages:writeStop sharing with that account.
POST /pages/{page}/teamspages:writeShare with one of your teams: {"team": <id>, "role": "editor"}.
DELETE /pages/{page}/teams/{team}pages:writeStop sharing with that team.

Only a page's owner changes or shares it; on a page shared with you these answer 403. Sharing follows the same rules as the dashboard: it needs a paid plan, everyone you share with takes one of your plan's seats, and a share past your seats is listed with "active": false and gives nothing until a seat frees up.

Teams

Method and pathNeedsWhat it does
GET /teamsteams:readYour teams, with member_count and page_count.
POST /teamsteams:writeCreate a team: {"name": "…"}. Needs the Team plan.
GET /teams/{id}teams:readIts members and pages.
PATCH /teams/{id}teams:writeRename it: {"name": "…"}.
DELETE /teams/{id}teams:writeDelete it.
POST /teams/{id}/membersteams:writeAdd the account of a login: {"email": "…"}.
DELETE /teams/{id}/members/{account}teams:writeRemove a member.

Alert channels

Method and pathNeedsWhat it does
GET /channelschannels:readYour channels.
POST /channelschannels:writeCreate one: {"kind": "webhook", "name": "…", "config": {…}}.
GET /channels/{id}channels:readOne channel.
PATCH /channels/{id}channels:writeChange its name or config. Settings left out keep their value.
DELETE /channels/{id}channels:writeDelete it.
POST /channels/{id}/testchannels:writeSend a test alert (five a minute).

Settings by kind: email to; webhook url, secret; slack url; discord url; telegram token, chat_id; ntfy url, token. The webhook secret, the Slack and Discord webhook URLs and the Telegram and ntfy tokens are secret: they are never returned, and secrets_set names the ones that have a value. Slack, Discord, Telegram and ntfy need a paid plan. See Alert channels for what each sends.

Pixels

Method and pathNeedsWhat it does
GET /pixelspixels:readYour pixels, each with its url, the tag to paste, and its hit count.
POST /pixelspixels:writeCreate one: {"name": "…"}.
GET /pixels/{id}pixels:readOne pixel and its newest loads (?limit=, default 50, up to 200).
DELETE /pixels/{id}pixels:writeDelete it and its loads.
PUT /pixels/{id}/imagepixels:writeServe an image instead of the invisible GIF: send the PNG, GIF, JPEG or WebP file as the body. On plans with pixel images.
DELETE /pixels/{id}/imagepixels:writeGo back to the invisible GIF.

Events

Method and pathNeedsWhat it does
GET /eventsevents:readStatus changes across your own monitors, newest first (?limit=, default 50, up to 200).

Monitor fields

POST /monitors and PATCH /monitors/{id} take the same fields. All are optional on a change; a new monitor needs a name.

FieldKindMeaning
name, tags, descriptionbothTags are space-separated.
kindbothheartbeat (default) or http. Only on create.
pagebothPage id. On a change, only the page's owner can move a monitor, and only to another of their own pages.
period, graceheartbeatDurations like 30m, 1h, 1d. Setting period on a cron monitor switches it back to a period.
cron, timezoneheartbeatA five-field cron expression and an IANA timezone, instead of period. An empty cron switches back to the period.
cost_alert_usdheartbeatAlert when one run reports a cost above this. 0 turns it off.
url, method, intervalhttpWhat to request (GET, HEAD or POST) and how often.
expected_status, keywordhttpThe status to expect (0 accepts any 2xx or 3xx) and text the body must contain.
timeout, fail_thresholdhttpSeconds (1 to 60), and failed checks in a row before it is down (1 to 10).
channelsbothIds of the alert channels to notify. On a change it replaces the channels you can see; other editors' channels stay.
publicbothShow it on the page's public status page.

Pages shared with you

On a page shared with you as an editor, monitors work like your own: they have an id and a ping_url, you can change, pause, resume and delete them, and a monitor you create there belongs to the page's owner and counts against their plan. On a page shared with you to view, a monitor comes back with its slug, name, kind, status and last ping or check, and without its id, ping URL, target or schedule, because a heartbeat's id is its ping URL. Address it with GET /pages/{page}/monitors/{slug}; an id route answers 404 for it, as it would for somebody else's monitor.

Examples

Create a heartbeat:

curl -X POST -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"name":"nightly-db-backup","kind":"heartbeat","period":"1d","grace":"30m","tags":"prod","channels":[3]}' \
  https://vivere.dev/api/v1/monitors

Use "cron":"0 2 * * *","timezone":"Europe/Berlin" instead of period for a cron schedule.

Create an HTTP check:

curl -X POST -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"name":"api health","kind":"http","url":"https://api.example.com/healthz","interval":"5m","expected_status":200,"keyword":"ok"}' \
  https://vivere.dev/api/v1/monitors

Give a monitor more grace and a cost alert:

curl -X PATCH -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"grace":"1h","cost_alert_usd":0.50}' https://vivere.dev/api/v1/monitors/<id>

Make a page for a client and share it with them to view:

curl -X POST -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"title":"Acme jobs"}' https://vivere.dev/api/v1/pages
curl -X POST -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"email":"ops@acme.example","role":"viewer"}' https://vivere.dev/api/v1/pages/<page>/shares

Add a Slack channel:

curl -X POST -H "Authorization: Bearer vv_…" -H "Content-Type: application/json" \
  -d '{"kind":"slack","name":"#ops","config":{"url":"https://hooks.slack.com/services/…"}}' \
  https://vivere.dev/api/v1/channels

Give a pixel an image:

curl -X PUT -H "Authorization: Bearer vv_…" --data-binary @logo.png https://vivere.dev/api/v1/pixels/<id>/image

Errors

Errors are {"error": "message"}, with the message written for a person to read:

StatusMeans
400The body is not JSON, or has a field the endpoint does not know.
401No key, an unknown key, or one that has expired.
402A plan limit: monitors, pages, pixels, seats, or a feature the plan does not have.
403The key lacks the permission the endpoint needs (the message names it), or only the page's owner can do this.
404Not found, or not something this key can see.
409A slug or name already in use, or a page that cannot be deleted yet.
422A value that is not valid, such as a period shorter than your plan allows.
429Rate limited: 60 requests a minute per address.