API Reference¶
Tracedown 0.4.50 and later
This page describes the API as served from release 0.4.50 on. Release 0.4.49
serves only GET /key under /api/public/v1.
Every endpoint of the key-authenticated API, version 1 — 72 in all,
under /api/public/v1 — plus the description at
/api/openapi/public/v1.json, which sits outside the namespace and needs no
key. The full request and response schemas are in that
OpenAPI document; this page is the map.
Conventions¶
- Paths are relative to
/api/public/v1. Every request carriesAuthorization: Bearer td_…. - Path ids are UUIDs; a malformed one is 400
invalid_uuid, withdetails.fieldnaming which id. The only path parameters that are not ids areresourceTypeandprincipalType, on the access endpoints. - Timestamps are ISO-8601 strings in UTC, except two numeric fields noted where they appear, which are epoch seconds.
- Creates answer
200with the created resource. Deletes answer200with{"ok": true}.POST /services/{id}/runanswers202; a few reads can answer204, noted per row. - Lists take
page(default 1) andpageSize(default 50, at most 100) and answer{items, total, page, pageSize}— written Page of X below. See Paging for their order. - Write endpoints — anything but
GETandHEAD— need a write key; a read key gets 403api_key_read_only.HEADis answered on everyGETendpoint. - Body: lists the request fields; a body that is not JSON, has the wrong
shape or fails a field's validation is 400
invalid_request_body, withdetails.fieldanddetails.reasonwhen the gateway can name the field. Errors: lists only the codes particular to an endpoint. Every endpoint can also answer the common ones.
Key¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/key |
Describes the calling key: name, prefix, access, expiry, and the organization and user it acts for. | 200 ApiKeyInfo |
Workspaces¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/workspaces |
Lists the workspaces the caller may see. | 200 Page of Workspace |
POST |
/workspaces |
Creates a workspace. Needs organization Workspaces Write. Body: name (required, ≤ 128).Errors: 403 insufficient_permissions; 409 already_exists. |
200 Workspace |
GET |
/workspaces/{id} |
Returns one workspace. | 200 Workspace |
PATCH |
/workspaces/{id} |
Renames a workspace. Body: name (≤ 128). |
200 Workspace |
DELETE |
/workspaces/{id} |
Deletes a workspace with everything in it. | 200 {"ok": true} |
PATCH |
/workspaces/{id}/services-toggle |
Switches every service in every project of the workspace on or off, in one transaction. Body: isActive (required). |
200 ToggleResult |
Projects¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/projects |
Lists the projects of a workspace that the caller may see. Query: workspaceId (required).Errors: 400 field_required when workspaceId is missing. |
200 Page of Project |
POST |
/projects |
Creates a project in a workspace. Body: workspaceId (required), name (required, ≤ 128).Errors: 409 already_exists. |
200 Project |
GET |
/projects/{id} |
Returns one project. | 200 Project |
PATCH |
/projects/{id} |
Renames a project. Body: name (≤ 128). |
200 Project |
DELETE |
/projects/{id} |
Deletes a project with its services. | 200 {"ok": true} |
PATCH |
/projects/{id}/services-toggle |
Switches every service in the project on or off, in one transaction. Body: isActive (required). |
200 ToggleResult |
Services¶
The script endpoints can refuse a script for what it targets. On a default
install (TRUSTED_DOMAIN_MODE=false) a domain the organization has not verified
is restricted:
| Code | Meaning |
|---|---|
unverified_domain_call_limit |
The script makes more than three calls while it targets an unverified domain. |
unverified_domain_includes |
The script uses an includes check while it targets an unverified domain. |
unverified_domain_interval |
The schedule is shorter than five minutes while the script targets an unverified domain. |
All three are 400. Verify the domain under Settings → Domains; see Domain trust.
A script is also refused with 400 blocked_probe_target when it targets an
address no probe may reach (private, loopback, internal-only, or a non-HTTP
scheme). Verifying a domain does not change that.
A script that does not validate is refused with 400 field_invalid and
details.field = script. details.errors lists every problem the validator
reported (each with code, callIndex, field and detail), and
details.reason gives the first one's message. This holds wherever a script is
saved or checked: create, update, /script and /toggle.
Write and check it in the dashboard's editor, or with a Lace validator (see
Writing Probes), before sending it.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/services |
Lists the services of a project that the caller may see. Query: projectId (required).Errors: 400 field_required when projectId is missing. |
200 Page of Service |
POST |
/services |
Creates a service in a project, switched off. A script in the body is saved as a first script save, which switches the service on unless isActive is false. isActive: false keeps it off. When the script or the enable is refused, the call leaves nothing behind — no service, no audit entries.Body: projectId (required), name (required, ≤ 128), label (≤ 32), schedule (cron, ≤ 16, default */5 * * * *), saveResponseBodies (default true), script (≤ 65536), isActive.Errors: 409 already_exists; script errors as for /script; enabling errors as for /toggle. |
200 Service |
GET |
/services/{id} |
Returns one service. | 200 Service |
PATCH |
/services/{id} |
Updates a service's configuration; fields left out are unchanged. A script here needs version.Body, all optional: name (≤ 128), label (≤ 32), schedule (≤ 16), probeMode (consecutive, simultaneous, random), queuePolicy (skip, enqueue_once), serviceWindow (≤ 256), saveResponseBodies, script (≤ 65536), version.Errors: 400 field_required (a script without version), field_invalid (a malformed serviceWindow), unverified_domain_interval; 409 version_conflict; script errors as for /script. |
200 Service |
DELETE |
/services/{id} |
Deletes a service. | 200 {"ok": true} |
PATCH |
/services/{id}/script |
Replaces the Lace script. Validated before it is saved; the service's version goes up by one. The first save of a service that has never been saved (still at version 1) switches it on; if that enable is refused, the script is still saved and the service stays off.Body: script (required, ≤ 65536), version (required — the version being replaced).Errors: 400 field_invalid (the script does not validate: details.field = script, with details.errors and details.reason), blocked_probe_target, unverified_domain_call_limit, unverified_domain_includes, unverified_domain_interval; 409 version_conflict. |
200 Service |
GET |
/services/{id}/snapshot |
The service and its most recent runs, in one read. | 200 ServiceSnapshot |
PATCH |
/services/{id}/toggle |
Switches the service on or off. Switching on needs a valid script. Body: isActive (required).Errors: 400 field_required (no script), field_invalid (the script does not validate, with details.errors and details.reason). |
200 Service |
POST |
/services/{id}/run |
Asks for one run now, outside the schedule. The result appears under /results when it lands — see Running a service now.Errors: 409 service_inactive, script_missing. |
202 {"ok": true, "requestedAt": "…"} |
GET |
/services/{id}/agents |
The agent slugs the service may run on. An empty list means any agent. | 200 list of slugs |
PUT |
/services/{id}/agents |
Replaces the agents the service may run on. An empty list means any agent. Body: slugs (required, list).Errors: 400 field_invalid with details.unknown listing slugs that name no agent the caller can use — unknown, inactive or not visible to them. |
200 list of slugs |
Agents¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/agents |
Lists the active probe agents the caller can name in PUT /services/{id}/agents, by slug and label, ordered by slug — nothing about where they are or how they are doing. |
200 list of Agent |
Variables¶
The same endpoints exist at four scopes:
| Scope | {scope} prefix |
Permission it needs |
|---|---|---|
| Organization | (empty) — so /variables |
Organization Settings Read to list, Write to change |
| Workspace | /workspaces/{id} |
Read on the workspace to list, write to change |
| Project | /projects/{id} |
Read on the project to list, write to change |
| Service | /services/{id} |
Read on the service to list, write to change |
In the paths below, {scope} is one of the prefixes above. Values come back
masked; see Variables.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
{scope}/variables |
Lists the scope's variables. Errors: 403 insufficient_permissions (organization scope). |
200 Page of Variable |
POST |
{scope}/variables |
Creates a variable. Body: key (required, ≤ 64), value (required, ≤ 4096), type (variable default, secret, metric).Errors: 400 variable_limit_reached, reserved_key (not at organization scope); 403 insufficient_permissions (organization scope); 409 already_exists. |
200 Variable |
PATCH |
{scope}/variables/{varId} |
Replaces a variable's value. Body: value (required, ≤ 4096).Errors: 400 readonly_variable (not at organization scope); 403 insufficient_permissions (organization scope). |
200 Variable |
DELETE |
{scope}/variables/{varId} |
Deletes a variable. Errors: 400 system_variable (not at organization scope); 403 insufficient_permissions (organization scope). |
200 {"ok": true} |
GET |
{scope}/variables/hierarchy |
Every variable the resource sees, from its own scope up to the organization's, with each scope's computed, read-only variables. Workspace, project and service scope only: the organization has nothing above it. | 200 VariableHierarchy |
Results¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/services/{id}/results |
Lists the service's runs, newest first. Query: since (ISO-8601: runs started at or after it). |
200 Page of ResultSummary |
GET |
/services/{id}/results/{resultId} |
Returns one run with all of its steps. | 200 Result |
GET |
/services/{id}/results/{resultId}/steps/{stepId}/body |
The response body the step stored, inline. See Step bodies and the answers below. | 200 StepBody; 204 |
Step body answers¶
| Status | Code | Meaning |
|---|---|---|
| 200 | — | The body, as StepBody. |
| 204 | — | The step has no stored body (hasBody is false): none was saved, or retention or a forgotten store has since cleared it. bodyNotStoredReason on the step says which. |
| 410 | body_gone |
The step still records a body and the object is not there — deleted from its storage outside Tracedown, or no longer inside the store it was recorded in. Final: there is nothing to retry. |
| 413 | body_too_large |
The stored body is over the 4 MiB inline cap. details.maxBytes says what the cap is. |
| 503 | body_store_unavailable |
The storage holding the body did not answer within 15 seconds, or no read slot came free within 10 seconds because the gateway was already reading as many bodies as it allows at once. Answers carry Retry-After: 10. The body is probably still there; try again after that. |
410 and 503 are deliberately different answers: the first says the body is
gone, the second says it could not be reached just now. See
Body Stores for the
operator's side.
Metrics¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/services/{id}/metrics |
Current counters and state of the service. | 200 ServiceMetrics; 204 while it has none |
GET |
/services/{id}/metrics/history |
Hourly buckets for the service. Query: hours (default 24, 1–168). |
200 list of HourlyBucket |
GET |
/services/{id}/metrics/statistics |
Uptime, error rate, latency trend and per-endpoint breakdown over a window. Query: window: 24h (default), 7d, 30d, 90d. |
200 Statistics |
GET |
/services/{id}/metrics/statistics/endpoint-series |
The window per endpoint over time, on the same buckets. Query: window. |
200 EndpointSeries |
GET |
/services/{id}/metrics/statistics/assertions |
The window's most-failing assertions, with how far back it actually read (since, truncated).Query: window. |
200 AssertionFailures |
GET |
/services/{id}/metrics/statistics/failure-heatmap |
Failed runs by UTC hour of day and ISO weekday. Query: days (default 90, 1–365). |
200 FailureHeatmap |
GET |
/projects/{id}/metrics |
Current counters and state across the project's services the caller may see. | 200 ServiceMetrics with serviceCount; 204 when there is no data |
GET |
/projects/{id}/metrics/history |
Hourly buckets across those services. Query: hours (default 24, 1–168). |
200 list of HourlyBucket |
GET |
/workspaces/{id}/metrics |
Current counters and state across the workspace's projects the caller may see. | 200 ServiceMetrics with projectCount and serviceCount; 204 when there is no data |
GET |
/workspaces/{id}/metrics/history |
Hourly buckets across those projects. Query: hours (default 24, 1–168). |
200 list of HourlyBucket |
An out-of-range hours, days or window is 400 field_invalid naming the
parameter.
Silences¶
These are the calling user's own notification silences — what the bell icons in the dashboard set — not an organization-wide mute. See Silences & Quiet Hours.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/silences |
Lists the caller's silences. | 200 Page of Silence |
POST |
/silences |
Creates a silence for the caller. Body: channel (required: email, all or quiet-hours), at most one of workspaceId, projectId, serviceId, config (JSON as a string), quietHours (RRULE[/minutes[/timezone]]).Errors: 400 field_invalid (channel webhook, more than one resource, malformed quiet hours or config); other unknown channels are invalid_request_body. |
200 Silence |
GET |
/silences/{id} |
Returns one of the caller's silences. | 200 Silence |
PATCH |
/silences/{id} |
Changes a silence's channel, configuration or quiet hours. Body, all optional: channel, config, quietHours.Errors: 400 field_invalid. |
200 Silence |
DELETE |
/silences/{id} |
Removes one of the caller's silences. | 200 {"ok": true} |
Access¶
Who may see or change a workspace, project or service. resourceType is
workspace, project or service; a principal is a user (by user id, as
the members list gives it) or a group. Every call here needs
write on the resource. See
Resource grants.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/access/{resourceType}/{resourceId} |
Lists the users and groups granted access to the resource, and at which level. Errors: 400 field_invalid (resource type). |
200 list of AccessEntry |
PUT |
/access/{resourceType}/{resourceId} |
Grants a user or group access, or changes the level of an existing grant. Body: principalType (user or group), principalId, permissions (1 read, 2 write).Errors: 400 field_invalid (resource type). |
200 {"ok": true} |
DELETE |
/access/{resourceType}/{resourceId}/{principalType}/{principalId} |
Removes a user's or group's grant on the resource. Errors: 400 field_invalid. |
200 {"ok": true} |
Directory¶
Read-only: where a client finds the ids it grants access to. Both need organization Users Read.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/members |
Lists the organization's members, disabled ones included (pending invitations are not members). Errors: 403 insufficient_permissions. |
200 Page of Member |
GET |
/groups |
Lists the organization's groups, with member counts. Errors: 403 insufficient_permissions. |
200 Page of Group |
Webhooks¶
Attaching the organization's existing webhooks to a workspace, project or service. Webhooks themselves are created and edited in the dashboard; here they are read-only, and redacted. Listing webhooks needs organization Webhooks Read. Listing a resource's bindings also needs read on that resource; creating one needs Webhooks Write and write on the resource — a resource the caller cannot read or write is 404. Changing or removing a binding needs Webhooks Write.
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/webhooks |
Lists the organization's webhooks: id, name, label, method and creation time — never the URL, headers, body or configuration. Errors: 403 insufficient_permissions. |
200 Page of Webhook |
GET |
/webhooks/bindings |
Lists the webhooks bound to a resource. Query: resourceType (required: workspace, project, service), resourceId (required).Errors: 400 field_required naming the missing parameter, field_invalid for an unknown resourceType; 403 insufficient_permissions. |
200 Page of WebhookBinding |
POST |
/webhooks/bindings |
Binds a webhook to a resource. Query: resourceType, resourceId (both required).Body: webhookId (required), enabled (default true).Errors: 400 field_required, field_invalid for an unknown resourceType; 403 insufficient_permissions; 409 binding_exists. |
200 WebhookBinding |
PATCH |
/webhooks/bindings/{id} |
Pauses or resumes a binding. Body: enabled (required).Errors: 400 field_required without enabled; 403 insufficient_permissions. |
200 WebhookBinding |
DELETE |
/webhooks/bindings/{id} |
Removes a binding. The webhook itself stays. Errors: 403 insufficient_permissions. |
200 {"ok": true} |
The API description¶
| Method | Path | What it does | Answers |
|---|---|---|---|
GET |
/api/openapi/public/v1.json |
The OpenAPI 3.1 description of everything above. No key; metered per address. Note the path: it is not under /api/public/v1. |
200 OpenAPI document |
Response shapes¶
The fields each response carries, in brief. Types, nullability and the nested objects in full are in the OpenAPI document.
ApiKeyInfo¶
id, name, prefix, access (read or write), expiresAt (null when it
never expires), organization {id, name}, user {id, email}.
Workspace¶
id, name, createdAt.
Project¶
id, workspaceId, name, createdAt, serviceCount, and metrics (a
ServiceMetrics object, when there is data).
Service¶
id, projectId, name, label, script, schedule, probeMode,
queuePolicy, serviceWindow, saveResponseBodies, isActive, lastStatus,
lastStatusSince, version (send it back with a script change),
createdAt, unverifiedTargets, and when available metrics and
lastFailure (the failed assertions of the latest failing run).
ServiceSnapshot¶
service (a Service) and recentProbes: a list of {status,
avgResponseMs, callCount, failedCalls, timestamp} — timestamp in
epoch seconds.
ToggleResult¶
matched, changed, unchanged, skipped (a list of {serviceId, name,
reason}), skippedTotal, skippedByReason.
Agent¶
slug, label.
Variable¶
id, key, value, type (variable, secret or metric), masked
(true when value is the mask rather than the value — see
Variables), systemType (set on the
variables Tracedown seeds itself), createdAt, updatedAt.
VariableHierarchy¶
scopes: one entry per scope from the resource up to the organization, each
with scope, prefix (how a script addresses it, such as $w.),
resourceId, resourceName, editable, variables (a list of
Variable) and locked (that scope's computed, read-only
variables such as $s.name, each {key, value, description}).
ResultSummary¶
id, status, runDurationMs, totalResponseMs, startedAt, agentSlug.
Result¶
id, serviceId, status, runDurationMs, startedAt, probeAgentId,
agentSlug, rawResult, and steps. Each step has id, stepNum,
requestUrl, statusCode, responseTimeMs, the phase timings (dnsMs,
connectMs, tlsMs, ttfbMs, transferMs), responseSizeBytes, error,
assertionResults, headers, hasBody and bodyNotStoredReason.
rawResult follows the Lace ProbeResult format, with storage locators blanked
(calls[].response.bodyPath and keys like it are null); a step's body is read
through hasBody and the body endpoint, never from rawResult.
StepBody¶
content, contentType (null when none was recorded or it is not one the
gateway repeats back), encoding (null for
text as it is, "base64" otherwise). See Step bodies.
ServiceMetrics¶
counters {probesTotal, probesSuccess, probesFailure, probesTimeout},
state {lastStatus, lastConsecutive, lastResponseMs, lastRunAt — in
epoch seconds}, percentiles {p50, p95, p99}, and on project and
workspace metrics serviceCount and projectCount.
HourlyBucket¶
hour, total, success, failure, timeout, sumMs, callCount.
Statistics¶
window, bucketType, overall (buckets of {bucketStart, p50Ms,
p95Ms, p99Ms, uptimePct, errorRatePct, probeCount}), regions (the
same buckets per agent), endpoints (per endpoint: calls, status-code counts,
phase timings against the previous window, average size), and
endpointsTruncated.
EndpointSeries¶
window, bucketType, buckets, all (every endpoint together),
endpoints (per endpoint: key, method, template, points), and
endpointsTruncated.
AssertionFailures¶
window, since, until, truncated, and assertions: per assertion, the
endpoint, what it checked, failures, evaluations, failureRatePct and
lastFailedAt.
FailureHeatmap¶
days, timezone, since, until, coveredFrom, coveredTo, totalRuns,
totalFailedRuns, and cells of {weekday, hour, runs, failedRuns}.
Silence¶
id, orgUserId, workspaceId, projectId, serviceId (at most one set),
channel, config, quietHours, resourceName.
AccessEntry¶
principalType, principalId, name, email (for users), permissions
(1 read, 2 write).
Member¶
userId, displayName, email, isActive.
Group¶
id, name, memberCount.
Webhook¶
id, name, label, method, createdAt.
WebhookBinding¶
id, webhookId, webhookName, enabled, createdAt.