Inference is down
Pulse confirmed an outage after repeated failed checks
Started 08:14 UTC
Cause HTTP 529
Pulse Documentation
Deploy the app, drive it from pulsectl, and extend with
your agents.
1.0 Introduction
Pulse is a self-hosted uptime monitor. It checks your public HTTP endpoints every minute, confirms failures before alerting, records every incident with its full state history, and publishes a public status page.
Everything is driven through one control plane: the
dashboard, the pulsectl CLI, and the HTTP API all speak
the same versioned contract with the same permissions model. A human
clicking "Pause" and an agent calling
POST /api/v1/monitors/api/pause
perform the identical operation.
pulsectl) for terminals, scripts, and agents
Pulse is serverless end to end. There is no long-running process to babysit.
/api/cron/check-monitors every minute. The
scheduler packs due monitors into one batch, checks them
concurrently, and resolves state transitions atomically.
/api/cron/maintenance, runs daily at
03:17. It compacts routine checks, builds rollups, and snapshots
database usage.
Monitor states
A monitor moves through UP →
VERIFYING_DOWN
→ DOWN →
VERIFYING_UP
→ UP. Failures are confirmed over consecutive
checks (the failure threshold) before an incident opens, and
recoveries are confirmed the same way before it resolves.
Monitors can also be
PENDING, PAUSED, or
ARCHIVED.
2.0 Automated setup
Point a coding agent at the prompt below and it discovers your active projects, provisions Vercel, Neon, Edge Config, and Resend, deploys Pulse, and configures monitoring end to end. Run it directly with the codex tab, or copy the plain prompt for Claude Code, OpenClaw, Hermes, or any other agent runner.
codex \
-m gpt-5.6-sol \
-c model_reasoning_effort='"low"' \
--sandbox danger-full-access \
--ask-for-approval on-request \
"$(cat <<'PROMPT'
Act as the deployment owner for Pulse, the self-hosted uptime monitor at https://github.com/0xSMW/pulse-uptime: inspect the repository, documentation, `.env.example`, migrations, deployment configuration, CLI manifest, and OpenAPI spec; identify every active public web project the user owns or maintains by inspecting available workspaces, repositories, deployment providers, project metadata, configured domains, production environments, and existing infrastructure, verify each endpoint is genuinely active and production-facing, then deploy Pulse and configure monitoring for all of them without waiting for the user to enumerate URLs. Establish the correct Vercel team and project, create and configure Neon Postgres, Vercel Edge Config, and Resend, verify the sending domain, generate independent high-entropy application secrets, set the one-time bootstrap token, apply migrations through the direct connection, run the full verification suite, and deploy production. Determine the user’s commonly used work email from authoritative account metadata, repository identities, deployment-provider profiles, domain ownership, and existing project configuration; use the strongest consistent match to claim the first administrator account, asking only when multiple plausible addresses remain unresolved. Generate a unique password with at least 24 random characters, store the email, password, Pulse URL, creation date, and recovery notes in the user’s available password manager when supported; otherwise create a clearly named local credentials file outside the repository with owner-only permissions, never print its contents to chat, logs, shell history, or command output, report its exact path, and instruct the user to import it into their password manager and securely delete the file afterward. Remove the bootstrap token and migration-owner credential from the runtime environment after account creation. Build a complete grouped configuration covering every discovered active web project and its meaningful health endpoints, using appropriate intervals, timeouts, expected status ranges, failure thresholds, recovery thresholds, and recipients; validate, plan, review, and apply it through `pulsectl`, automatically applying additive and non-destructive changes while requiring explicit user approval only for destructive operations. Run a live test for every monitor, investigate and correct failed checks where access permits, verify `/api/v1/version`, `/openapi/v1.json`, `/status`, cron authentication, database health, monitoring activation, and end-to-end outage, recovery, and test-email delivery. Use least-privilege credentials, preserve existing production infrastructure, keep all secrets out of source control and agent transcripts, and pause only when an external login, billing consent, domain verification, secret entry, unresolved administrator-email ambiguity, or destructive-change approval requires the user. Finish with the Pulse URL, public status-page URL, administrator email used, secure credential-storage location, every project and endpoint monitored, resources created, configuration applied, live-test results, verification evidence, unresolved blockers, and exact commands for future administration.
PROMPT
)"
Act as the deployment owner for Pulse, the self-hosted uptime monitor at https://github.com/0xSMW/pulse-uptime: inspect the repository, documentation, .env.example, migrations, deployment configuration, CLI manifest, and OpenAPI spec; identify every active public web project the user owns or maintains by inspecting available workspaces, repositories, deployment providers, project metadata, configured domains, production environments, and existing infrastructure, verify each endpoint is genuinely active and production-facing, then deploy Pulse and configure monitoring for all of them without waiting for the user to enumerate URLs. Establish the correct Vercel team and project, create and configure Neon Postgres, Vercel Edge Config, and Resend, verify the sending domain, generate independent high-entropy application secrets, set the one-time bootstrap token, apply migrations through the direct connection, run the full verification suite, and deploy production. Determine the user’s commonly used work email from authoritative account metadata, repository identities, deployment-provider profiles, domain ownership, and existing project configuration; use the strongest consistent match to claim the first administrator account, asking only when multiple plausible addresses remain unresolved. Generate a unique password with at least 24 random characters, store the email, password, Pulse URL, creation date, and recovery notes in the user’s available password manager when supported; otherwise create a clearly named local credentials file outside the repository with owner-only permissions, never print its contents to chat, logs, shell history, or command output, report its exact path, and instruct the user to import it into their password manager and securely delete the file afterward. Remove the bootstrap token and migration-owner credential from the runtime environment after account creation. Build a complete grouped configuration covering every discovered active web project and its meaningful health endpoints, using appropriate intervals, timeouts, expected status ranges, failure thresholds, recovery thresholds, and recipients; validate, plan, review, and apply it through pulsectl, automatically applying additive and non-destructive changes while requiring explicit user approval only for destructive operations. Run a live test for every monitor, investigate and correct failed checks where access permits, verify /api/v1/version, /openapi/v1.json, /status, cron authentication, database health, monitoring activation, and end-to-end outage, recovery, and test-email delivery. Use least-privilege credentials, preserve existing production infrastructure, keep all secrets out of source control and agent transcripts, and pause only when an external login, billing consent, domain verification, secret entry, unresolved administrator-email ambiguity, or destructive-change approval requires the user. Finish with the Pulse URL, public status-page URL, administrator email used, secure credential-storage location, every project and endpoint monitored, resources created, configuration applied, live-test results, verification evidence, unresolved blockers, and exact commands for future administration.
Full access, minimal gating
This grants filesystem and network access and only pauses for logins, billing consent, secrets, and destructive changes. Run it against infrastructure you own, and read the plan before it applies anything.
3.0 Getting started
One Next.js project, one Neon database, one Edge Config, and a Resend key. About fifteen minutes from clone to first check.
Link the repository to the Vercel team that will own the deployment, then run the inspect command to confirm the project landed in that team before creating any resources.
vercel link --yes --project pulse-uptime --scope <team>
vercel project inspect pulse-uptime --scope <team>
Use the pooled connection string as
DATABASE_URL
and the direct one as
DATABASE_URL_UNPOOLED, then apply migrations over
the direct connection.
neonctl projects create --name pulse-uptime
neonctl connection-string --project-id <project-id> --pooled
neonctl connection-string --project-id <project-id>
# apply migrations with the direct URL in .env.local
set -a; source .env.local; set +a
pnpm db:migrate
Create an Edge Config named pulse-uptime in the
same team and seed the single monitoring key with a
valid empty configuration.
{
"schemaVersion": 1,
"configVersion": 0,
"settings": {
"concurrency": 25,
"defaultTimeoutMs": 8000,
"defaultFailureThreshold": 2,
"defaultRecoveryThreshold": 2,
"defaultRecipients": [],
"userAgent": "Pulse/1.0"
},
"monitors": []
}
Verify the sending domain, create a sending-only API key, and
set RESEND_API_KEY and
RESEND_FROM_EMAIL. You can finish setup without
email. The readiness screen flags missing email keys as a
warning, not a blocker, and alerts stay unverified until a test
message is delivered (pulsectl notification test).
Set PORKBUN_API_KEY and
PORKBUN_SECRET_KEY
as server-only variables. In
Settings → System → Domain monitoring, check
the connection and enable the signed webhook. Pulse polls
registration facts and receives domain.renewed
and domain.expiring events at
/api/webhooks/porkbun. Porkbun never manages SSL.
Generate three independent random values of at least 32 bytes.
# one value per secret, never reuse
openssl rand -base64 32 # CRON_SECRET
openssl rand -base64 32 # API_TOKEN_HASH_KEY
openssl rand -base64 32 # DEVICE_AUTH_SECRET
pnpm verify
vercel deploy --prod --scope <team>
After deploying, confirm /api/v1/version,
/openapi/v1.json, and /status respond,
then complete first-run onboarding at your deployment URL:
create the administrator account, verify readiness, and activate
monitoring.
The canonical list lives in .env.example. Values are
validated at boot.
| Variable | Required | Purpose |
|---|---|---|
| DATABASE_URL | Yes | Pooled Neon Postgres connection string used by the app. |
| DATABASE_URL_UNPOOLED | Yes | Direct connection string, required for migrations. |
| EDGE_CONFIG | Yes | Edge Config read connection string. |
| EDGE_CONFIG_ID | Yes | Edge Config to write accepted configuration to. |
| VERCEL_API_TOKEN | Yes | Token authorized to update the Edge Config. |
| VERCEL_PROJECT_ID | No |
Present in .env.example but not currently
read by the app.
|
| VERCEL_TEAM_ID | No | Team that owns the Edge Config. Set it when the Edge Config is team-owned. |
| RESEND_API_KEY | Recommended | Resend key (re_…) for alert email. |
| RESEND_FROM_EMAIL | Recommended |
Verified sender, e.g.
Pulse <alerts@superposition.app>.
|
| CRON_SECRET | Yes | Authenticates Vercel Cron requests. ≥ 32 characters. |
| API_TOKEN_HASH_KEY | Yes | Keyed hashing for API token digests and purpose-derived encryption for protected provider data. ≥ 32 characters. |
| PORKBUN_API_KEY | No | Server-only Porkbun API credential for domain facts. |
| PORKBUN_SECRET_KEY | No | Server-only Porkbun secret for domain facts. |
| DEVICE_AUTH_SECRET | Yes | Signs the CLI device-authorization flow. ≥ 32 characters. |
| NEXT_PUBLIC_APP_URL | Yes | Canonical deployment URL. |
| NEXT_PUBLIC_STATUS_PAGE_NAME | No | Public status page title. Defaults to “Pulse Status”. |
Pulse sends exactly three kinds of email, all from
RESEND_FROM_EMAIL. When the failure threshold
confirms an outage, every recipient on the monitor gets one
message. When the recovery threshold confirms the fix, they get
one more. Delivery runs through a durable outbox, so retries never
duplicate a message.
Pulse confirmed an outage after repeated failed checks
Started 08:14 UTC
Cause HTTP 529
Pulse confirmed the endpoint is responding again
Recovered 08:31 UTC
Duration 17m
Pulse Uptime can deliver outage and recovery alerts
Subject: Pulse notification test
pulsectl notification test
The subject line is the headline: a monitor named Inference pages
you as “Inference is down”. Both incident emails deep-link to
/incidents/:id, and that is the whole surface. There
are no digests, reminders, or marketing follow-ups.
Default secure, but production needs a few extra operator-side controls tightened.
Run under a least-privilege database role.
Create a dedicated Postgres login with only the grants the app
needs, and point the pooled DATABASE_URL at it. Keep
the Neon owner (neondb_owner) and the unpooled
DATABASE_URL_UNPOOLED
credential for migrations only, and remove it from the application
environment so the running app never authenticates as the schema
owner.
Add the browser security headers. Production ships HSTS. Add the rest of the central policy so the dashboard is defended in depth.
| Header | Value |
|---|---|
| Content-Security-Policy |
Restrict script/style/connect sources and set
frame-ancestors.
|
| X-Frame-Options |
DENY
— legacy clickjacking defense alongside
frame-ancestors.
|
| X-Content-Type-Options | nosniff |
| Referrer-Policy | strict-origin-when-cross-origin |
| Permissions-Policy | Deny the browser features the app does not use. |
| Strict-Transport-Security | Already shipped in production. |
Claim the first admin immediately.
A fresh deployment boots into onboarding with no administrator.
Claim the initial account the moment the deploy is live so no one
else can. Creating that first admin requires a one-time bootstrap
credential supplied through the
PULSE_BOOTSTRAP_TOKEN
environment variable; set it before first run, use it to create
the admin, then remove it.
Rotate provider secrets and scope them tightly.
Generate fresh values for RESEND_API_KEY,
CRON_SECRET, DEVICE_AUTH_SECRET, and
API_TOKEN_HASH_KEY
for your own deployment rather than reusing any shared value, and
scope the Resend key to sending only.
Install the CLI only from the official source.
Until signed release artifacts exist, build
pulsectl
from source with Go and nothing else.
go install github.com/0xSMW/pulse-uptime/cli/cmd/pulsectl@latest
4.0 Application
Six screens, no configuration sprawl. Everything the app can do is also available from the CLI and API.
/onboarding
A fresh deployment boots straight into onboarding. A readiness
gate checks Vercel, the database, Edge Config, and email before
anything else, then three steps create the administrator account,
add a first monitor, and verify a live check before activating it.
A closing screen hands off to the CLI and agent tokens. Sign in
afterwards at /login.
/The home screen lists every monitor with its live state, 24-hour uptime, check timeline, and latency. A health banner summarizes the whole system, and the ⌘K command palette jumps anywhere or runs quick actions. New Monitor opens a sheet that asks for four fields: name, URL, group, and interval. Method, timeout, expected status, and thresholds are tucked behind Advanced.
/monitors/:id
One monitor's full story: the current state with its confirmation
progress, a segmented check timeline, a latency chart, and recent
transitions. Pause, resume, edit, test, and archive actions live
here. Archiving keeps history. Re-create a monitor with the same
id, through the API or config apply, and it comes
back.
/incidents
Every failure gets a durable record. The list filters by monitor
and resolution state. The detail view (/incidents/:id) shows the cause, the event trail of every state transition with
timestamps, and which notifications were delivered. Incidents open
only after the failure threshold confirms an outage, so flapping
checks don't page you.
/settingsFour areas, one per sidebar item:
/settings/system
Porkbun supplies registration expiry and auto-renew for covered
domains. The System card runs every ten minutes and reads the
Porkbun portfolio for due domains, normally once per 24 hours. It
accepts signed domain.renewed and
domain.expiring
webhooks. Expiry alerts are off by default and notify default
recipients at 30 and 14 days. Certificate checks remain direct TLS
probes. Certificate alerts are out of scope.
/status
A public, indexable status page that revalidates every 30 seconds,
with per-group views at /status/:group. It shows
current operational state per monitor without exposing internal
detail. The page title comes from
NEXT_PUBLIC_STATUS_PAGE_NAME.
5.0 CLI
One Go binary for monitors, incidents, status, tokens, and complete configuration. Humans link through the browser and agents use scoped tokens.
go install github.com/0xSMW/pulse-uptime/cli/cmd/pulsectl@latest
pulsectl me --server https://pulse.superposition.app
Build the CLI from source with Go until signed release artifacts
are published. Replace the example URL with your deployment.
pulsectl me
triggers an interactive browser approval on first run and stores
the session in your operating-system keyring. Once linked, it
reports who you are and which scopes you hold.
Interactive linking uses an OAuth-style device flow:
/cli/authorize on the server,
where you confirm the code as a signed-in administrator.
pulsectl auth login # link this installation
pulsectl auth status # inspect the current session
pulsectl auth unlink --yes # remove it
# headless environments: pass a scoped token instead
export PULSECTL_TOKEN=pulse_live_...
echo "$PULSECTL_TOKEN" | pulsectl monitor list --token-stdin
No token flag, on purpose
pulsectl accepts tokens only through the environment or stdin, so secrets stay out of shell history and process listings.
Contexts are named server profiles stored in local config, so one binary can drive several Pulse deployments.
pulsectl context add production --url https://pulse.superposition.app --use
pulsectl context add staging --url https://staging.superposition.app
pulsectl context list
pulsectl monitor list --context staging
Settings resolve in precedence order: flags, then environment, then the active context.
| Flag | Env | Purpose |
|---|---|---|
| --context | PULSECTL_CONTEXT | Named context to use for this invocation. |
| --server | PULSECTL_URL | Server URL, overriding the context. |
| -o, --output | PULSECTL_OUTPUT |
Output format: table, json,
jsonl, yaml, tsv.
|
| --timeout | PULSECTL_TIMEOUT | Per-request timeout. |
| --token-stdin | PULSECTL_TOKEN | Read a bearer token from stdin / the environment. |
| --no-color | NO_COLOR | Disable ANSI color. |
| --debug | None | Verbose request diagnostics on stderr. |
Every command declares the API scope it needs, the same scopes you
grant to tokens. authenticated means any signed-in
principal.
| Command | Purpose | Scope |
|---|---|---|
| me | Show the current principal or link this installation. | authenticated |
| auth login | status | unlink | Link, inspect, or unlink an installation and revoke its credentials. | authenticated |
| context add | list | show | use | remove | Manage named server profiles (local only). | None |
| status | Public service status snapshot. | status:read |
| monitor list | get | watch |
Read monitors. watch streams state changes.
|
monitors:read |
| monitor create | update | Create or edit a monitor with flags mirroring the API fields. | monitors:write |
| monitor pause | resume | archive |
Lifecycle operations. archive preserves
history and asks for --yes.
|
monitors:write |
| monitor test | Run one live check now. Exits 4 if the target fails. | monitors:write |
| group list | List groups with monitor counts. | monitors:read |
| group create | rename | delete | Manage groups. Only empty groups can be deleted. | monitors:write |
| incident list | get | Read incident history and detail. | incidents:read |
| config export | schema | Export accepted configuration / print its JSON schema. | config:read |
| config validate | plan | apply | The declarative workflow. See §5. | config:write |
| token create | list | revoke | Manage scoped API tokens. | tokens:manage |
| notification test | Send a test email to confirm delivery. | notifications:test |
| version | CLI version plus server compatibility check. | None |
| doctor | Diagnose config, context, connectivity, and auth. | None |
| completion | help |
Shell completions. help --output json emits a
machine-readable manifest.
|
None |
Data goes to stdout, diagnostics to
stderr. On a TTY the default is a table. When
piped, output defaults to json (jsonl
for monitor watch), so scripts never parse table art.
pulsectl monitor list -o json | jq '.[].id'
pulsectl monitor watch -o jsonl --state DOWN
pulsectl incident list -o yaml
Exit codes are typed so scripts and agents can branch without parsing messages.
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Unexpected error. |
| 2 | Invalid input: a bad flag, malformed value, or unusable file. |
| 3 | Authentication required or the session is no longer valid. |
| 4 |
Operational failure, such as
monitor test
against a failing target.
|
| 5 | Not found. |
| 6 | Conflict: the resource changed underneath you (stale ETag, duplicate id). |
| 7 | Permission denied: the principal lacks the required scope. |
| 8 | Rate limited. Retry after the server-provided delay. |
| 9 | Server unavailable or unreachable. |
| 10 | Partial success. |
| 130 | Interrupted with Ctrl-C. |
Agents get the same control plane as people. Create a scoped token
in Settings → Access and export three variables.
The CLI then runs without a browser, and
help --output json
hands your agent a manifest of every command, flag, and required
scope.
export PULSECTL_URL=https://pulse.superposition.app
export PULSECTL_TOKEN=pulse_live_...
export PULSECTL_OUTPUT=json
pulsectl help --output json # machine-readable command manifest
pulsectl config schema # JSON schema for the config document
pulsectl monitor list
Use pulsectl --help to discover commands. Authenticate through
PULSECTL_TOKEN, prefer --output json, and never print or persist
the token.
6.0 Configuration
The entire monitoring setup (settings, groups, and monitors) is one declarative document you can export, diff, review, and apply. Terraform style, with conflict detection and destructive-change approval built in.
version: 2
settings:
concurrency: 25
defaultTimeoutMs: 8000
defaultFailureThreshold: 2
defaultRecoveryThreshold: 2
defaultRecipients:
- codex@superposition.app
userAgent: Pulse/1.0
groups:
- id: production
name: Production
monitors:
- id: api
name: API
url: https://inference.superposition.app/health
enabled: true
groupId: production
method: GET
intervalMinutes: 1
timeoutMs: 8000
expectedStatus: { minimum: 200, maximum: 299 }
failureThreshold: 2
recoveryThreshold: 2
recipients: []
| Field | Constraints |
|---|---|
| id |
Kebab-case, 3-64 chars (^[a-z0-9]+(-[a-z0-9]+)*$). Stable, since it names the monitor in the API and CLI.
|
| name | 1-80 characters. |
| url |
Public http(s) URL without embedded
credentials. Private and reserved addresses are rejected.
|
| method | GET or HEAD. |
| intervalMinutes | 1, 5, 10, or 15. |
| timeoutMs | 1000-15000. |
| expectedStatus |
Inclusive range, each bound 100-599,
maximum ≥ minimum.
|
| failureThreshold | 1-5 consecutive failed checks before an incident opens. |
| recoveryThreshold | 1-5 consecutive passing checks before it resolves. |
| recipients | Up to 20 unique email addresses. |
| groups |
Up to 100, each { id, name }. Monitors
reference groupId.
|
Monitor ids must be unique, at most 100 monitors may be enabled, and the document may not exceed 55 KB. Exporting a v1 document automatically upgrades it to the v2 group format.
pulsectl config export --file monitors.yaml
# edit monitors.yaml
pulsectl config validate --file monitors.yaml
pulsectl config plan --file monitors.yaml
pulsectl config apply --file monitors.yaml --wait
validate
checks the document against the schema and semantic rules without
touching the server state. plan computes an exact
diff plus content hashes of the base and target. The diff covers
settings changes. For groups it lists creates, renames, and
deletes. For monitors it lists creates, field-level updates,
pauses, resumes, and archives. apply submits the plan
and, with --wait, polls the resulting operation until
it is accepted (written to Edge Config) or
rejected.
If-Match
along with the base, target, and plan hashes. If anyone changed
configuration in between, the apply fails with a conflict
instead of silently clobbering.
destructiveConsentRequired. Non-interactive applies
must state intent twice:
--allow-destructive --yes.
Review plans like code
Treat config plan output as a pull-request diff
for your monitoring. Agents should run plan and show the diff
to a human before applying.
7.0 API reference
Everything the dashboard and CLI do goes through
/api/v1. The full machine-readable spec is served by
your deployment at /openapi/v1.json.
The base URL is your deployment. Pulse is self-hosted, so there is no shared api.pulse.dev. Every response is a typed envelope:
{
"apiVersion": "v1",
"kind": "MonitorList",
"data": [ ],
"meta": {
"requestId": "req_01j8zqf7",
"nextCursor": null
}
}
kind names the payload
shape: Monitor, MonitorList,
Incident, ConfigurationPlan,
Error, and so on.
limit and cursor.
Follow meta.nextCursor until it is
null.
Idempotency-Key
header containing a UUID. Retries with the same key return the
original result.
meta.requestId for
correlation.
curl https://pulse.superposition.app/api/v1/monitors \
-H "Authorization: Bearer $PULSE_TOKEN"
Three principal types share one permission model:
pulsectl token create. They carry exactly the
scopes you grant, require an explicit expiry of at most 365 days
(the CLI defaults to 90d), and are stored only as keyed digests.
Requests without credentials get 401 with a
WWW-Authenticate
header. Authenticated requests missing a scope get
403
with error code
SCOPE_DENIED.
{
"apiVersion": "v1",
"kind": "Error",
"error": {
"code": "SCOPE_DENIED",
"message": "This operation requires monitors:write.",
"details": {},
"requestId": "req_01j8zqf7"
}
}
Rate limits are per principal over a five-minute window:
600 reads
and 120 mutations. Exceeding either returns
429
with a
Retry-After
header. Validation failures return
400
with field-level detail in
error.details. Concurrency conflicts (stale
If-Match, duplicate ids, reused idempotency keys with
different bodies) return 409.
/api/v1/version
Supported API versions plus the minimum and latest compatible CLI versions. Unauthenticated, used by pulsectl for compatibility checks and by deploy verification.
{
"apiVersion": "v1",
"kind": "Version",
"data": {
"supportedApiVersions": ["v1"],
"minimumCliVersion": "0.3.0",
"latestCliVersion": "0.3.2"
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/me
Who is calling: principal type, email or token identity, granted scopes, and the linked CLI installation when the caller is a device session.
authenticated{
"apiVersion": "v1",
"kind": "Me",
"data": {
"principalType": "api_token",
"email": null,
"tokenId": "0d9f6c1e-…",
"tokenName": "ci-agent",
"scopes": ["monitors:read", "incidents:read"],
"installation": null
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/monitors
List monitors, sorted by state by default so
problems surface first.
| Query | Description |
|---|---|
| state |
UP, DOWN,
VERIFYING_UP,
VERIFYING_DOWN, PENDING,
PAUSED, ARCHIVED.
|
| group, groupId | Filter by group name or id. |
| enabled | true or false. |
| sort |
state
(default), name, or id.
|
| limit, cursor | Pagination. |
curl "https://pulse.superposition.app/api/v1/monitors?state=DOWN" \
-H "Authorization: Bearer $PULSE_TOKEN"
# equivalent
pulsectl monitor list --state DOWN -o json
{
"apiVersion": "v1",
"kind": "MonitorList",
"data": [
{
"id": "api",
"name": "API",
"url": "https://inference.superposition.app/health",
"enabled": true,
"group": "Production",
"groupId": "production",
"method": "GET",
"intervalMinutes": 1,
"timeoutMs": 8000,
"expectedStatus": { "minimum": 200, "maximum": 299 },
"failureThreshold": 2,
"recoveryThreshold": 2,
"recipients": ["codex@superposition.app"],
"state": "DOWN"
}
],
"meta": { "requestId": "req_01j8zqf7", "nextCursor": null }
}
/api/v1/monitors
Create a monitor. id, name, and
url
are required. Everything else falls back to the global
defaults. Field constraints are the same as the
config file.
curl -X POST https://pulse.superposition.app/api/v1/monitors \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id": "console", "name": "Console", "url": "https://console.superposition.app"}'
# equivalent
pulsectl monitor create --id console --name "Console" --url https://console.superposition.app
/api/v1/monitors/ { monitorId}
Fetch one monitor, including its live state and
timestamps.
curl https://pulse.superposition.app/api/v1/monitors/api \
-H "Authorization: Bearer $PULSE_TOKEN"
/api/v1/monitors/ { monitorId}
Partial update. Send only the fields you are changing. Group
assignment uses groupId (or null to
clear).
curl -X PATCH https://pulse.superposition.app/api/v1/monitors/api \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"intervalMinutes": 5, "timeoutMs": 10000}'
/api/v1/monitors/ { monitorId}
Archive the monitor. History is preserved. Re-creating the same id restores it.
monitors:writecurl -X DELETE https://pulse.superposition.app/api/v1/monitors/api \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"
/api/v1/monitors/ { monitorId}/pause
Stop checking without losing state. The companion
POST
…/resume
re-enables checks.
curl -X POST https://pulse.superposition.app/api/v1/monitors/api/pause \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"
curl -X POST https://pulse.superposition.app/api/v1/monitors/api/resume \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"
/api/v1/monitors/ { monitorId}/test
Run one live check immediately without affecting monitor state, ideal for verifying a fix before resuming.
monitors:write{
"apiVersion": "v1",
"kind": "MonitorTest",
"data": {
"successful": true,
"method": "GET",
"finalUrl": "https://inference.superposition.app/health",
"statusCode": 200,
"latencyMs": 42,
"redirectCount": 0,
"errorCode": null,
"errorMessage": null
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/groups
List groups with their monitor counts.
monitors:read{
"apiVersion": "v1",
"kind": "GroupList",
"data": [
{ "id": "production", "name": "Production", "monitorCount": 4 }
],
"meta": { "requestId": "req_01j8zqf7", "nextCursor": null }
}
/api/v1/groups
Create a group with a stable kebab-case id and a
display name.
curl -X POST https://pulse.superposition.app/api/v1/groups \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id": "marketing", "name": "Marketing"}'
/api/v1/groups/ { groupId}
Rename a group. The id is permanent. Only
name
changes.
curl -X PATCH https://pulse.superposition.app/api/v1/groups/marketing \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name": "Marketing Site"}'
/api/v1/groups/ { groupId}
Delete an empty group. Groups still containing monitors return a conflict.
monitors:writecurl -X DELETE https://pulse.superposition.app/api/v1/groups/marketing \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"
/api/v1/incidents
Incident history, newest first, with limit/cursor
pagination.
{
"apiVersion": "v1",
"kind": "IncidentList",
"data": [
{
"id": "8f4e2c10-…",
"monitorId": "api",
"openedAt": "2026-07-12T08:14:00Z",
"resolvedAt": "2026-07-12T08:31:00Z"
}
],
"meta": { "requestId": "req_01j8zqf7", "nextCursor": null }
}
/api/v1/incidents/ { incidentId}
Full incident detail: cause, duration, and the event trail of every state transition and notification.
incidents:readcurl https://pulse.superposition.app/api/v1/incidents/8f4e2c10-… \
-H "Authorization: Bearer $PULSE_TOKEN"
# equivalent
pulsectl incident get 8f4e2c10-…
/api/v1/status
The service status snapshot that also powers the public status page: overall state plus per-monitor operational status.
status:readcurl https://pulse.superposition.app/api/v1/status \
-H "Authorization: Bearer $PULSE_TOKEN"
# equivalent
pulsectl status
The API surface behind
plan & apply. Exports carry an
ETag. Applies send it back as If-Match.
/api/v1/config
Export the accepted configuration document with its
ETag
and content hash.
curl -i https://pulse.superposition.app/api/v1/config \
-H "Authorization: Bearer $PULSE_TOKEN"
# ETag: "sha256:2c26b46b…"
/api/v1/config/schema
The JSON Schema for the configuration document, so agents can validate locally before submitting.
config:readpulsectl config schema -o json
/api/v1/config/validate
Validate a candidate document against schema and semantic rules. Never mutates state.
config:write{
"apiVersion": "v1",
"kind": "ConfigurationValidation",
"data": { "valid": true, "errors": [] },
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/config/plan
Diff a candidate document against the accepted configuration.
Returns base/target/plan hashes, the categorized diff, and
destructiveConsentRequired.
{
"apiVersion": "v1",
"kind": "ConfigurationPlan",
"data": {
"baseConfigHash": "sha256:2c26…",
"targetConfigHash": "sha256:9d1a…",
"planHash": "sha256:77b0…",
"diff": {
"settingsChanged": [ ],
"groupCreates": [ ],
"groupUpdates": [ ],
"groupDeletes": [ ],
"creates": [ ],
"updates": [ ],
"pauses": [ ],
"resumes": [ ],
"archives": [ ],
"unchanged": [ ]
},
"destructiveConsentRequired": false
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/config/apply
Apply a previously planned change. Requires
If-Match
with the export ETag and the three hashes from the plan.
Destructive plans also require
allowDestructiveChanges: true. Returns an
operation to poll.
curl -X POST https://pulse.superposition.app/api/v1/config/apply \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-H 'If-Match: "sha256:2c26…"' \
-d '{
"baseConfigHash": "sha256:2c26…",
"targetConfigHash": "sha256:9d1a…",
"planHash": "sha256:77b0…",
"targetConfig": { … },
"allowDestructiveChanges": false
}'
/api/v1/config/operations/ { operationId}
Poll an apply operation. States: written →
accepted
once Edge Config confirms, or
rejected
/ failed.
{
"apiVersion": "v1",
"kind": "ConfigurationOperation",
"data": { "id": "b3a9e0d2-…", "state": "accepted" },
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/tokens
Create a scoped token. The secret appears once in the response and is stored only as a keyed digest. Copy it immediately.
tokens:managepulsectl token create --name ci-agent \
--scope monitors:read --scope incidents:read \
--expires-in 90d
{
"apiVersion": "v1",
"kind": "CreatedToken",
"data": {
"id": "0d9f6c1e-…",
"name": "ci-agent",
"token": "pulse_live_…",
"scopes": ["monitors:read", "incidents:read"],
"expiresAt": "2026-10-16T00:00:00Z"
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/tokens
List tokens with scopes, expiry, revocation, and last-used timestamps. Secrets are never returned again.
tokens:managepulsectl token list --all
/api/v1/tokens/ { tokenId}
Revoke a token immediately. Revocation is permanent.
tokens:managepulsectl token revoke 0d9f6c1e-… --yes
/api/v1/notifications/test
Send a test email through the configured Resend sender to confirm delivery end to end.
notifications:testpulsectl notification test --recipient codex@superposition.app
The device flow behind pulsectl auth login. You
rarely call these directly, but they're documented for custom
clients.
/api/v1/cli-auth/device
Start a device authorization for a named installation. Returns the user code and verification URIs. The code expires in 10 minutes.
{
"apiVersion": "v1",
"kind": "DeviceAuthorization",
"data": {
"deviceCode": "d5c1…",
"userCode": "BQTV-XKGF",
"verificationUri": "https://pulse.superposition.app/cli/authorize",
"verificationUriComplete": "https://pulse.superposition.app/cli/authorize?code=BQTV-XKGF",
"expiresIn": 600,
"interval": 5
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/cli-auth/token
Poll with the deviceCode every
interval
seconds until the administrator approves in the browser. The
response then carries the bearer session token.
{
"apiVersion": "v1",
"kind": "CliSession",
"data": {
"token": "pulse_cli_…",
"tokenType": "Bearer",
"expiresAt": "2026-10-16T00:00:00Z",
"scopes": ["monitors:read", "monitors:write", "…"]
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/cli-auth/revoke
Revoke the calling installation, its CLI sessions, and
descendant API tokens. This is what
pulsectl auth unlink
uses.
pulsectl auth unlink --yes
/api/v1/database-health
Storage budget usage, per-category byte counts, retention
windows for each data category, and the governor's mode (FULL_DETAIL
through ESSENTIALS_ONLY). Health is one of
HEALTHY, WATCHING,
OPTIMIZING, PROTECTING,
CRITICAL, or UNKNOWN.
{
"apiVersion": "v1",
"kind": "DatabaseHealth",
"data": {
"health": "HEALTHY",
"summary": "Storage remains within its configured budget",
"budgetBytes": 500000000,
"usedBytes": 118000000,
"governor": {
"mode": "FULL_DETAIL",
"action": "None required",
"lastCompactionAt": "2026-07-18T03:17:00Z"
}
},
"meta": { "requestId": "req_01j8zqf7" }
}
/api/v1/database-health/refresh
Request a new usage measurement. Measurements are cached for
15 minutes, so a call inside that window returns the cached
snapshot. data.refresh.status reports which you
got: CURRENT, CACHED, or
STALE_FALLBACK.
curl -X POST https://pulse.superposition.app/api/v1/database-health/refresh \
-H "Authorization: Bearer $PULSE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"