API reference#

The JSON API a monitor agent uses to enroll with a tenpm uptime server, sync its assigned check set, and report results and status back. Generated from docs-site/assets/tenpmuptime-monitor.yaml — see that file’s header for how it’s kept in sync with the code.

Download the raw OpenAPI spec (tenpmuptime-monitor.yaml)

The JSON API a monitor agent uses to enroll with a tenpm uptime server, sync its assigned check set, and report results and status back. This is the wire contract described in internal/model and implemented by internal/server/api_handlers.go; both binaries build against the same Go structs today, so treat this document as generated-by-hand from that code, not the other way around — if the two disagree, the code is right and this file is stale. Every route except POST /api/enroll requires the monitor's own API key, minted at enrollment. POST /api/enroll requires an enrollment token instead (an org token or a platform token — see the security scheme below), since no monitor exists yet at that point. Error responses across every endpoint are a plain-text body (one line) with a non-2xx status, not a JSON envelope — the handlers use Go's http.Error. The 4xx/5xx responses below document status code and body meaning; there is no shared error schema.

v1.0.0

Servers#

Local dev server
http://127.0.0.1:8002

Security#

A monitor's own API key, issued once by POST /api/enroll and persisted by the agent alongside its minted monitor id.
apiKeyAuth
http bearer
An enrollment token minted by an org (from its "Add a monitor" page) or, for the shared fleet, a platform token minted by an admin — the latter expires one hour after minting. Only POST /api/enroll accepts this token kind; every other endpoint requires a monitor API key instead.
enrollmentTokenAuth
http bearer

API#

Sync the caller's assigned check set#

Returns every check the authenticated monitor should run whose updated_at is strictly after since — including checks that have become deleted: true or been unassigned, so the agent can stop running them, and, for a private-definition check, a row with its definition fields blank (see Check's description).

Store the response's server_time, not the caller's own clock, as the new watermark for the next call's since — using a local clock risks a sync gap under clock skew between the two machines.

Request (requires apiKeyAuth)#

GET /api/checks

Query parameters#

Parameter nameValueDescriptionAdditional
sincestring (date-time)RFC3339 timestamp; defaults to the Unix epoch (i.e. "everything") when omitted. Must be a server_time value returned by a previous call to this endpoint, not a locally-generated one.

Responses#

200: The delta since since.

Schema: ChecksResponse

PropertyTypeRequiredDescription
checksarray of Checkyes
server_timestring (date-time)yesStore this as the watermark for the next call's since.

400: since was present but not a valid RFC3339 timestamp.

Schema: string

401: Missing/malformed Authorization header, or an unknown API key.

Schema: string

403: The monitor is disabled.

Schema: string

Enroll a monitor#

A monitor's one-time self-registration into the org (or shared fleet) named by the enrollment token it presents. Which of the two the token resolves to is a property of the credential, never of the request body — an agent cannot ask to be shared.

id is optional and means "reclaim the monitor you already know by this id" (used after an enrollment reset); a fresh agent omits it and is minted a new, globally unique id. All other fields are required.

The response's api_key is shown/returned exactly once — it is not retrievable again, only reset (which mints a new one and invalidates the old).

Request (requires enrollmentTokenAuth)#

POST /api/enroll

Request body (required)#

Schema: EnrollRequest

PropertyTypeRequiredDescription
citystringyes
countrystringyes
idstringnoOmit to enroll as a new monitor. Set to reclaim a previously enrolled monitor by id after an enrollment reset.
namestringyes
regionstringyes

Responses#

200: Enrolled (or reclaimed) successfully.

Schema: EnrollResponse

PropertyTypeRequiredDescription
api_keystringyesShown once. Persist it; it cannot be retrieved again, only reset (which invalidates this value and mints a new one).
monitor_idstringyesMinted by the server (twelve characters of lowercase Crockford base32), globally unique across every org and the shared fleet. Persist this and pass it back as id only to reclaim this same monitor later.

400: Malformed JSON, oversized body, or a required field (name/region/country/city) missing.

Schema: string

401: Missing/malformed Authorization header, or the enrollment token is unknown, revoked, or expired (all three look identical to the caller on purpose).

Schema: string

404: id was set but no monitor with that id exists in the token's organisation. The agent should omit id to enroll as new rather than silently becoming a second node.

Schema: string

409: id was set but that monitor is already enrolled.

Schema: string

Authenticated heartbeat#

A trivial call whose only effect is what the auth middleware already did before the handler ran: updating the monitor's last_seen_at.

Request (requires apiKeyAuth)#

GET /api/ping

Responses#

200: OK.

Schema: OKResponse

PropertyTypeRequiredDescription
statusstringno

401: Missing/malformed Authorization header, or an unknown API key.

Schema: string

403: The monitor is disabled.

Schema: string

Upload a batch of check execution results#

Every result's monitor_id is stamped from the authenticated caller server-side; whatever the payload contains for it is ignored, so an agent cannot report results as a different monitor. A result for a check the caller is no longer assigned to is silently dropped (not an error) rather than rejected — the rest of the batch still lands, and a stale or racing unassignment must not surface as a client bug.

Insertion is idempotent, so a retried batch (e.g. after a timed-out response whose write actually succeeded) cannot double-count.

A shared monitor's batch may legitimately span several organisations in one call, since one shared agent runs checks assigned by many different orgs; a private monitor's batch belongs entirely to its own org.

Request (requires apiKeyAuth)#

POST /api/results

Request body (required)#

Schema: ResultsRequest

PropertyTypeRequiredDescription
resultsarray of ResultyesMore than 500 in one call is rejected outright; a monitor with a larger local buffer loops the call instead.

Responses#

200: Results accepted. accepted may be less than the number of results submitted, since unassigned-check results are dropped silently rather than counted or rejected.

Schema: ResultsResponse

PropertyTypeRequiredDescription
acceptedintegeryesMay be less than the number of results submitted, since unassigned-check results are dropped silently rather than counted or rejected.

400: Malformed JSON, or more than 500 results in one batch.

Schema: string

401: Missing/malformed Authorization header, or an unknown API key.

Schema: string

403: The monitor is disabled.

Schema: string

413: Request body exceeded the 1 MiB cap for this endpoint.

Schema: string

Report a monitor's periodic self-health snapshot#

Shown on the server's Monitors page. The monitor_id this updates is the authenticated caller's own id, never taken from the body.

Request (requires apiKeyAuth)#

POST /api/status

Request body (required)#

Schema: MonitorStatus

PropertyTypeRequiredDescription
last_outage_ended_atstring (date-time)noAbsent until the agent has completed at least one internet- connectivity outage since it started (see monitor.ConnectivityGate). Only completed outages are reported — while offline the agent cannot call this endpoint at all.
last_outage_secintegerno
unsent_resultsintegeryesHow many results are stuck in the agent's local buffer.
uptime_secintegeryes
versionstringyes

Responses#

200: Accepted.

Schema: OKResponse

PropertyTypeRequiredDescription
statusstringno

400: Malformed JSON, or a negative unsent_results/uptime_sec/last_outage_sec.

Schema: string

401: Missing/malformed Authorization header, or an unknown API key.

Schema: string

403: The monitor is disabled.

Schema: string

Models#

Check#

A monitored target, as synced from server to monitor. url's scheme selects the check type: http/https fetch the URL (optional basic-auth userinfo), tcp://host:port tests that a TCP connect succeeds.

For a private-definition check (one whose definition has been wiped from the server — see private-checks-design.md), the server sends url, match_string, post_data, and headers as empty/absent: the real definition lives only in a JSON file loaded locally into the agent via -import-private-check, out of band from this API.

PropertyTypeRequiredDescription
deletedbooleanyesTrue means stop running this check; it is not removed from the delta so the agent learns about the deletion at all.
disable_redirectsbooleannoStop following an http(s) redirect chain; evaluate the first response as-is. Not meaningful for tcp checks.
down_interval_secintegernoServer-side alerting parameter; monitors receive it over sync but ignore it.
enabledbooleanyes
guidstringyesThe only identifier for this check that crosses the wire. The server's internal integer id never does.
headersobjectnoExtra request headers for http(s) checks, at most 10 entries.
interval_secintegeryes
match_modestringnoOmitted/absent means contains, so rows predating this field keep their old semantics.
match_stringstringyesEmpty asserts nothing about response content. Otherwise matched against the HTTP body, or (for tcp:// checks) the banner the service volunteers on connect.
max_response_time_msintegernoWhen set, a response arriving after this many milliseconds fails the check even if it otherwise passed. 0/absent means no such constraint.
namestringyes
post_datastringnoWhen non-empty, turns an http(s) check into a POST with this body.
result_detail_max_charsintegeryesCaps how many characters of a Result's error/ response_sample this check's results may carry. Always present (0 is a meaningful "send nothing", not "absent").
status_code_opstringnoWhen set, replaces the built-in "status >= 400 fails" rule with an explicit comparison against status_code_value. Absent means the built-in rule, not "no constraint". Not meaningful for tcp checks.
status_code_valueintegerno
timeout_secintegernoBounds one execution of the check. 0/absent means the default (10s); maximum 60s.
updated_atstring (date-time)yesFixed-width fractional seconds (see model.TimestampLayout) so lexical and chronological order agree; used as the since cursor.
urlstringyes

ChecksResponse#

PropertyTypeRequiredDescription
checksarray of Checkyes
server_timestring (date-time)yesStore this as the watermark for the next call's since.

EnrollRequest#

PropertyTypeRequiredDescription
citystringyes
countrystringyes
idstringnoOmit to enroll as a new monitor. Set to reclaim a previously enrolled monitor by id after an enrollment reset.
namestringyes
regionstringyes

EnrollResponse#

PropertyTypeRequiredDescription
api_keystringyesShown once. Persist it; it cannot be retrieved again, only reset (which invalidates this value and mints a new one).
monitor_idstringyesMinted by the server (twelve characters of lowercase Crockford base32), globally unique across every org and the shared fleet. Persist this and pass it back as id only to reclaim this same monitor later.

MonitorStatus#

A monitor's self-reported health snapshot, sent periodically. Shown on the server's Monitors page.

PropertyTypeRequiredDescription
last_outage_ended_atstring (date-time)noAbsent until the agent has completed at least one internet- connectivity outage since it started (see monitor.ConnectivityGate). Only completed outages are reported — while offline the agent cannot call this endpoint at all.
last_outage_secintegerno
unsent_resultsintegeryesHow many results are stuck in the agent's local buffer.
uptime_secintegeryes
versionstringyes

OKResponse#

PropertyTypeRequiredDescription
statusstringno

Result#

One check execution outcome, as reported from monitor to server.

PropertyTypeRequiredDescription
check_guidstringyesThe check this result is for. A result built on the monitor side must set this and never a server-internal id (there is none to send).
errorstringnoEmpty on success.
http_statusintegeryes
latency_msintegeryes
monitor_idstringyesIgnored on write — the server stamps the authenticated caller's own id regardless of what is sent here.
ran_atstring (date-time)yes
response_samplestringnoLeading characters of what the target sent back (HTTP body, or a tcp check's banner), capped both by the agent before sending and again by the server on ingest at result_detail_max_chars, regardless of what the payload claims.
successbooleanyes

ResultsRequest#

PropertyTypeRequiredDescription
resultsarray of ResultyesMore than 500 in one call is rejected outright; a monitor with a larger local buffer loops the call instead.

ResultsResponse#

PropertyTypeRequiredDescription
acceptedintegeryesMay be less than the number of results submitted, since unassigned-check results are dropped silently rather than counted or rejected.