Skip to content

REST API

Manage monitors, rules, incidents and callback endpoints over HTTPS. To send beats, see Publish a heartbeat. Every operation is listed in the API reference.

  • Origin: https://api.signalsitter.com
  • Base path: /v1
  • Auth: Authorization: Bearer <your API credential>
  • Contract: the OpenAPI document, also served at GET /v1/openapi.json
  1. Open the dashboard, pick a project, and create an API credential. Use read for read-only work. Managing callback endpoints needs manage.
  2. Copy the secret into your secret store. It’s shown once.
  3. Load it into SIGNALSITTER_API_KEY and set the origin:
Terminal window
export SIGNALSITTER_API_BASE=https://api.signalsitter.com

List your monitors:

Terminal window
curl --fail-with-body \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
"$SIGNALSITTER_API_BASE/v1/monitors"

Create a monitor that expects a beat every day, with ten minutes of grace:

Terminal window
curl --fail-with-body \
--request POST \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{"name":"Nightly backup","intervalSeconds":86400,"graceSeconds":600,"callback":{"kind":"organization_default"}}' \
"$SIGNALSITTER_API_BASE/v1/monitors"

The response carries publishUrl, the address to send beats to, and monitorKey, the monitor’s ID. Use that ID as {monitorId} in every other monitor route.

An API credential belongs to the project it was created in. Every request made with it acts in that project, so there is nothing to send.

  • To work in another project, create a credential in that project.
  • A Signalsitter-Project header naming a different project is refused with signalsitter.not_found.
  • Signed-in dashboard sessions name their project in Signalsitter-Project.

Listing projects with an API credential returns only that credential’s project. Project names are unique in an organization, ignoring case and extra spaces, so creating a duplicate returns signalsitter.conflict. See List projects, Create project and Rename project.

Only name is required at creation. Also accepted:

  • intervalSeconds: 60 to 31,536,000. Leave it out and the monitor measures its own cadence from the beats it receives.
  • graceSeconds: lateness tolerated after the interval. Values below 60 are raised to 60.
  • jurisdiction: unrestricted, eu, us or fedramp. It can’t change later.
  • callback: where alerts go. See callback bindings.

Then:

  • Watch for the first beat with Wait for first beat. It returns waiting, then accepted with the first acceptance time and next deadline.
  • Check a sample beat without recording anything with Test a beat.

To change a monitor, read it first. The response’s ETag header carries its configuration version, such as "configuration-3". Send it back in If-Match:

Terminal window
curl --fail-with-body \
--request PATCH \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
--header "Content-Type: application/json" \
--header 'If-Match: "configuration-3"' \
--data '{"patch":{"graceSeconds":900}}' \
"$SIGNALSITTER_API_BASE/v1/monitors/nightly-backup"

Fields you leave out of patch keep their current values. The callback binding has its own route, below.

Change lifecycle takes one action and the same If-Match:

  • pause: beats are still recorded, but no deadlines run and no incidents open.
  • resume: the clock restarts with a full interval plus grace.
  • archive: further beats are refused with signalsitter.monitor_archived. History is kept, and the monitor reports restorableUntil.
  • restore: counts against your plan’s active-monitor allowance. At the limit, free a slot or upgrade first.
  • enter_maintenance: needs a window with startsAt and endsAt, at most 30 days. Missed deadlines inside it don’t open incidents. The next deadline moves to the window’s end.
  • exit_maintenance: ends the window early and restarts the clock.

Delete monitor is permanent. It needs If-Match, closes open incidents and cancels pending callbacks.

Operation Returns
List monitors Every monitor with live status: lifecycle, last beat, next deadline, open incident
Get monitor Configuration, latest observation and the ETag
List observations Accepted beats, newest first
Read series Graph-ready minimum, maximum and mean per time bucket
List changes Configuration and lifecycle changes, with who made each one

Observations take optional since and until timestamps (RFC 3339). The series needs both, up to 365 days apart. On a paid plan, add includeObservationBuckets=true to read summarized history beyond 30 days.

If the same monitor ID exists in two jurisdictions, a request returns signalsitter.conflict. Retry with ?jurisdiction=eu (or the one you mean).

Set a numeric rule directly with a configuration update. This one opens an incident when files drops below 1:

{
"patch": {
"measurements": {
"files": {
"metricType": "count",
"minimum": 1,
"mode": "heartbeat",
"ruleAction": { "mode": "active", "version": 1 }
}
}
}
}

The rule kinds are minimum, maximum, maximumAbsoluteDelta, maximumPercentageDelta, zeroExpectation and ratio. The publish guide defines each one.

To see what a change would have caught before it goes live, use a draft:

  1. Create draft. It freezes a window of recent history.
  2. Update draft with the current expectedDraftVersion. Set a rule to null, or list it in disabledRules, to remove it.
  3. Replay draft to compare the incidents your current and proposed rules produce over that window. Nothing changes.
  4. Apply draft with confirm: true, expectedDraftVersion and expectedConfigurationVersion. If either is stale, you get signalsitter.precondition_failed. Re-read and try again.

Cancel draft closes a draft without touching the monitor.

List a monitor’s open incidents:

Terminal window
curl --fail-with-body \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
"$SIGNALSITTER_API_BASE/v1/monitors/nightly-backup/incidents?state=open"

States are open, recovering, recovered and resolved. List all incidents covers every monitor.

Each takes an optional {"note": "..."} body. Read what happened with Get timeline. Check notifications with List deliveries, and send one again with Redeliver.

Send notifications with callback endpoints

Section titled “Send notifications with callback endpoints”

A callback endpoint is a place alerts go, reusable across monitors: usually a webhook URL. Changing endpoints needs a manage credential.

Terminal window
curl --fail-with-body \
--request POST \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{"alias":"operations","url":"https://hooks.example.com/signalsitter"}' \
"$SIGNALSITTER_API_BASE/v1/callbacks"

Alerts can also reach people’s phones and messengers through WhooshBang. Set kind to whooshbang_subscriber and whooshbang.actorId to reach one person, or to whooshbang_group to reach everyone in your organization. Each person connects their own phone or messenger in the dashboard first. See Create endpoint for the fields.

  • The URL must be public HTTPS. A host that resolves to a private or reserved address is refused with signalsitter.callback_destination_rejected.
  • The response includes the signing secret once. Store it to verify deliveries.
  • Send test delivery sends one signed POST and reports what your receiver answered.
  • Set default endpoint with {"endpointId": "..."}, or null to clear it.
  • Update endpoint with "lifecycle": "disabled" stops deliveries. "active" starts them again.
  • Rotate signing secret keeps the old secret valid for overlapSeconds, 0 to 900 (default 300).
  • Remove endpoint is permanent.

A monitor’s callback binding says which endpoint its alerts go to. Set it with Set monitor binding:

binding Alerts go to
{"kind":"organization_default"} The default endpoint
{"kind":"named","alias":"operations"} That endpoint
{"kind":"inline","url":"https://..."} A URL used by this monitor only
{"kind":"disabled"} Nowhere

An inline URL returns its own signing secret once. Add "rotateSigningSecret": true to replace a lost one. Get monitor binding shows where alerts will go today, or why they can’t: no_organization_default, alias_not_found, endpoint_disabled or endpoint_removed.

Terminal window
curl --fail-with-body \
--header "Authorization: Bearer $SIGNALSITTER_API_KEY" \
--output export.ndjson \
"$SIGNALSITTER_API_BASE/v1/organization/export"
  • The default is JSON Lines: one record per line, each with a type. It holds monitors, observations, incidents, endpoint metadata and usage. It never holds secrets.
  • ?format=csv returns observations only, as a flat table.
  • If the stream stops, pass the cursor from the last checkpoint record as ?cursor=. The last checkpoint has complete: true.
  • ?includeObservationBuckets=true adds summarized history beyond 30 days on a paid plan.
  • Usage needs a credential with usage:read. Without it, an omitted record says so.
  • JSON: send bodies as application/json, up to 16 KiB. Gzip-compressed bodies (Content-Encoding: gzip) are accepted, and the limit applies after decompression. Other encodings get 415.
  • Pagination: lists take limit (1 to 200, default 50) and return nextCursor. Pass it back as cursor for the next page. No nextCursor means you’re on the last page.
  • ETags: reads return an ETag, such as "configuration-3" or "callback-endpoint-3". Changes to monitors, endpoints, credentials and project names need it in If-Match. A stale tag gets 412. A missing one gets 428.
  • Tracing: every response has X-Request-ID. Send your own X-Correlation-ID and it comes back on the response.

Errors are application/problem+json:

{
"type": "/docs/problems/not_found",
"title": "Resource not found",
"status": 404,
"detail": "The requested resource was not found.",
"code": "signalsitter.not_found",
"correlationId": "example-monitor-1",
"retryable": false
}

Validation failures add fieldErrors. Retryable problems add retryAfterSeconds and a Retry-After header.

Status code What to do
400 signalsitter.validation_failed Fix the fields named in fieldErrors.
401 signalsitter.authentication_required Send a valid credential.
403 signalsitter.permission_denied Use a credential with the right preset.
404 signalsitter.not_found Check the ID and project. Other organizations’ resources also return this.
409 signalsitter.conflict Re-read the resource, or add ?jurisdiction=.
409 signalsitter.idempotency_conflict Use a new key for a different request.
412 signalsitter.precondition_failed Re-read and send the new ETag.
413 signalsitter.payload_too_large Keep the body under 16 KiB.
415 signalsitter.unsupported_media_type Send application/json, plain or gzip.
428 signalsitter.precondition_required Add If-Match.
429 signalsitter.rate_limited Wait for Retry-After.
503 signalsitter.temporarily_unavailable Wait for Retry-After, then retry.

Every code has its own page, with what to do: see error codes.

Retry only when retryable is true, after Retry-After. For a write, retry with the same Idempotency-Key you sent the first time. Never mint a new key for a retry.

The API allows credentialed browser requests only from the SignalSitter dashboard. Call it from your server, not from a browser page.