Skip to main content

REST API

swamp serve exposes a REST API alongside its WebSocket interface. This page documents the available HTTP endpoints.

Authentication

REST API endpoints take a Bearer token in the Authorization header. The token is the same credential used for WebSocket authentication.

Authorization: Bearer <token>

The two health endpoints, GET /api/v1/health and GET /api/v1/health/stream, accept any valid server token and narrow what they return to what the token may read. Every other endpoint on this page except GET / and GET /health requires admin (admin on access:*) and answers 403 without it.

When --auth-mode is none (deprecated), no token is required.

See Monitor Server Health for how to mint a monitoring token.

Liveness Endpoint

GET / and GET /health

A liveness check. Both paths answer the same fixed body in every auth mode and do not require a Bearer token. They report nothing about the server's schedules, webhooks or instance; read those from GET /api/v1/health.

Response body

Field Type Description
status string Always "ok".
version string Always "1". It is not the Swamp version.

Response

Status Condition
200 The server is running.

Example

curl https://swamp.example.com/health
{ "status": "ok", "version": "1" }

Health Monitoring Endpoints

GET /api/v1/health

Returns a point-in-time JSON snapshot of node health. Any valid server token may read it; see What each token sees.

Response body

Field Type Description
instanceId string Unique identifier for the server instance.
deploymentMode string Deployment mode: local, durable, or durable (limited).
remoteOnly bool Whether the server is running in remote-only mode. When true, all steps must declare placement.
uptimeMs number Milliseconds since the server started.
ready bool Whether the instance is accepting work.
activeRuns array Active runs — each entry has runId, kind, resourceName, durationMs, principalId.
metrics object Sliding-window counters: windowMs (5 min), completions, failures, cancellations, throughputPerMinute, and latency (p50, p95, p99, or null with no completed runs).
workers array Each entry has name, instanceUuid, labels, platform, arch, swampVersion, status, connected, capacity, activeDispatchIds. Status is idle, busy, unverified, or draining.
scheduling object enabled flag and a schedules array — each entry has workflowId, workflowName, cronExpression, nextRun, running, and the schedule's queue state: queued (fires waiting to start), oldestQueuedAt (ISO-8601 time of the oldest waiting fire, or null) and lastQueueDelayMs (fire-to-start delay of the last run that started, or null). timeZone is the IANA time zone the scheduler evaluates cron expressions in, the serve host's local zone.
webhooks array Registered webhooks — each entry has route, workflow, scheme.
components array Health of internal subsystems (datastore, vault). Each entry has name, healthy, message, latencyMs, details.
retention object The repository's retention: automatic, configured, and a kinds array — each entry has kind, retention (or null when unset), and the last pass's cutoff, lastPassAt and complete (each null before any pass). Admin tokens only; absent when the read fails or takes longer than 2 seconds.

What each token sees

An admin token sees the full snapshot. Any other token sees:

  • activeRuns, scheduling.schedules and webhooks narrowed to the behaviors and workflows it may read (see Authorization), with principalId set to null on every run
  • workers and components empty, and no retention
  • instance fields (instanceId, deploymentMode, remoteOnly, ready), uptimeMs and metrics in full

One collected snapshot serves every reader for up to one second, so a snapshot can be up to a second old. After a tag edit that changes which grants match a behavior or workflow, a non-admin reader's view can take up to five seconds to follow. Grant changes apply at once.

Response

Status Condition
200 Health snapshot returned.
401 Missing or invalid Bearer token.
429 Request rate limit reached for the client or token; honour Retry-After.

Example

curl https://swamp.example.com/api/v1/health \
  -H "Authorization: Bearer health-monitor.secret"

GET /api/v1/health/stream

Server-Sent Events stream that pushes health snapshots at a configurable interval.

An initial snapshot is sent immediately on connect, then at the configured interval. Supports Last-Event-ID for resumable connections. Any valid server token may open a stream, and each snapshot is narrowed as described in What each token sees.

A token may hold at most 10 open streams, counted across every mint of the token name, and its principal at most 20 across all of its tokens. A stream beyond either limit is refused with 429.

Query parameters

Parameter Type Default Description
interval number 5000 Push frequency in milliseconds (min 1000, max 60000).

SSE format

id: 1
event: health
data: {"instanceId":"...","uptime":3600,...}

id: 2
event: health
data: {"instanceId":"...","uptimeMs":3605000,...}

The stream is a token session. When its token is revoked, rotated, or expires, or its principal loses access, the server sends a final session-ended event and closes the stream. The event has no id, and its data holds a close code and a reason:

event: session-ended
data: {"code":4003,"reason":"Session revoked: token revoked"}
Code Meaning
4002 The token expired. Mint a new token.
4003 The token was revoked, rotated, or deleted, or the principal lost access.
4004 The principal's group or collective membership changed. The token still works; reconnect.

A revoke on this instance ends the stream at once. A revoke on another instance takes effect at the next revalidation pass: up to 30 seconds plus the datastore poll interval. A close caused by the token itself — revoked, rotated, expired or deleted — records an auth.session.terminated audit event, as for WebSocket sessions. Consumers that ignore unknown event names are unaffected.

Headers

Includes X-Accel-Buffering: no for nginx reverse proxy compatibility.

Response

Status Condition
200 SSE stream opened.
401 Missing or invalid Bearer token.
429 Stream limit reached (10 per token name, 20 per principal), with Retry-After: 30; or the request rate limit was reached.

Example

curl -N https://swamp.example.com/api/v1/health/stream?interval=10000 \
  -H "Authorization: Bearer health-monitor.secret"

To resume after a disconnect:

curl -N https://swamp.example.com/api/v1/health/stream \
  -H "Authorization: Bearer health-monitor.secret" \
  -H "Last-Event-ID: 42"

GET /internal/runs

Returns all run records from the SQLite-backed RunTrackerStore, including completed, failed, and cancelled runs with full metadata.

Disabled by default. Enable with any of:

  • --enable-internal-api flag
  • enable-internal-api: true in the serve config file
  • SWAMP_ENABLE_INTERNAL_API=true environment variable

Returns 404 when not enabled.

Response

Status Condition
200 Run records returned.
401 Missing or invalid Bearer token.
403 The token is not admin.
404 Internal API not enabled (--enable-internal-api required).

Example

curl https://swamp.example.com/internal/runs \
  -H "Authorization: Bearer paul-token.secret"

Cancel Endpoints

Cancel a running execution via HTTP. These endpoints complement the CLI commands (swamp workflow cancel, swamp behavior cancel) for use by external tooling, CI/CD pipelines, or custom dashboards.

POST /api/v1/cancel/:type/:id

Cancel a single running execution by type and ID.

Parameter Value Description
:type workflow-run or method-run The execution type to cancel.
:id string The execution's run ID.

Response

Status Body Condition
200 { "status": "cancelled", "executionType": "...", "executionId": "..." } The execution was confirmed stopped — deregistered within the grace period.
200 { "status": "cancellation_requested", "executionType": "...", "executionId": "..." } The abort signal was delivered but the execution is still active — it has not yet deregistered within the grace period.
401 "Unauthorized: token required" or "Unauthorized" Missing or invalid Bearer token.
403 { "status": "error", "message": "Access denied: cancel requires admin permission" } The token is not admin.
404 { "status": "not_found", "message": "..." } No active execution with the given type/ID.

Example

curl -X POST https://swamp.example.com/api/v1/cancel/workflow-run/3f8a2b1c \
  -H "Authorization: Bearer paul-token.secret"

POST /api/v1/cancel

Cancel all running executions, optionally filtered by type.

Request body (optional)

Field Type Description
executionType string Filter by type: workflow-run or method-run. Omit to cancel all.
{ "executionType": "workflow-run" }

Response

Status Body Condition
200 { "status": "cancellation_requested", "count": <number> } Abort signals delivered. Returns the count of runs cancellation was requested for.
400 { "status": "error", "message": "executionType must be 'workflow-run' or 'method-run'" } Invalid executionType value.
401 "Unauthorized: token required" or "Unauthorized" Missing or invalid Bearer token.
403 { "status": "error", "message": "Access denied: cancel requires admin permission" } The token is not admin.

Example

# Cancel all running executions
curl -X POST https://swamp.example.com/api/v1/cancel \
  -H "Authorization: Bearer paul-token.secret"

# Cancel only workflow runs
curl -X POST https://swamp.example.com/api/v1/cancel \
  -H "Authorization: Bearer paul-token.secret" \
  -H "Content-Type: application/json" \
  -d '{"executionType": "workflow-run"}'