REST API
Tripwire's backend is a FastAPI JSON API. Everything the dashboard does, you can do over HTTP — author suites, start and observe runs, manage issues and settings, generate suites from a URL, export to Playwright, and read analytics.
- Base path:
/api/v1 - Auth: every endpoint requires
Authorization: Bearer <jwt-or-api-token>, except the open ones:GET /health,GET /health/ready,POST /auth/login, and the first-run bootstrapGET /auth/setup+POST /auth/setup(the latter only works while no users exist). See Authentication. - Interactive OpenAPI / Swagger UI:
/docs— try every endpoint live, with full request / response schemas. - Raw schema:
/openapi.json
The live OpenAPI page is the source of truth for exact request and response shapes — the tables below are a map, not a substitute. Generate clients from
/openapi.json.
Endpoints
Health
| Method | Path | Description |
|---|---|---|
GET | /health | Liveness — always 200 if serving. |
GET | /health/ready | Readiness — 200 if the data dir is writable, else 503. |
Auth
Full details in Authentication.
| Method | Path | Description |
|---|---|---|
GET | /auth/setup | Open. { needs_setup } — true while the instance has no admin yet. |
POST | /auth/setup | Open (only valid pre-first-user). { email, password } creates the first admin → { token, user }. |
POST | /auth/login | { email, password } → { token, user }. Open (no auth). |
GET | /auth/me | The current user. |
POST | /auth/tokens | Create an API token { name? } → returns the raw tw_… once. |
GET | /auth/tokens | List your API tokens (metadata only). |
DELETE | /auth/tokens/{id} | Revoke an API token. |
GET | /auth/users | List users (admin). |
POST | /auth/users | Create a user { email, password, role } (admin). |
Suites
| Method | Path | Description |
|---|---|---|
GET | /suites | List suites (paginated: limit, offset, q). |
POST | /suites | Create a new suite — body { yaml }. The server picks a unique filename (never overwrites). Returns { ok, file }. |
GET | /suites/{name} | Get a suite ({ file, yaml, cases }). |
PUT | /suites/{name} | Update a suite — body { yaml }; validates YAML, returns 400 on error. |
DELETE | /suites/{name} | Delete a suite. |
GET | /suites/{name}/export | Export the suite as a portable Playwright .spec.ts (text/plain). |
Runs
Runs are persisted to a durable queue and worked by a pool of up to TRIPWIRE_MAX_CONCURRENT_RUNS (default 2) workers — submit any number; they run in parallel up to that limit and the rest wait their turn (no 409). The queue survives a restart; a run interrupted by a crash is reconciled on the next startup. Each job is its own run id. State within a suite (generated fixtures and values a case capture:s) is shared across that suite's cases.
| Method | Path | Description |
|---|---|---|
GET | /runs | Run history (includes queued / running jobs). |
POST | /runs | Enqueue one or more jobs. Single-suite form: { suite, cases?, file_issues?, headed?, sharded? }. Queue form: { jobs: [{ suite, cases? }, …], file_issues?, headed? }. cases is a subset of case ids (omit for all). headed: true runs a visible browser. Returns { run_id, run_ids, queued }. |
GET | /runs/queue | Currently running + pending jobs — { active, active_suite, running: [{ id, suite }], running_suites, pending: [{ id, suite, cases }], busy } (active/active_suite keep the single-run shape for back-compat). |
GET | /runs/{id} | Run status + live events + report. Events include action (each LLM browser action) and shot (a per-step screenshot path). |
Run artifacts (per-step screenshots, reports) are served read-only under /api/v1/artifacts/<run_id>/…; each case in the report carries a shots[] list of { label, note, path } you can render from that base.
Plans (ordered regression passes)
A plan bundles suites into an ordered pass you run on demand or on a cron schedule.
| Method | Path | Description |
|---|---|---|
GET | /plans | List plans. |
GET | /plans/{plan_id} | Plan detail (suites, schedule, last run). |
POST | /plans | Create/update a plan — body { id?, name, description?, items: [{ suite, cases? }], schedule?, auth? } (schedule is a cron expression; set id to update). |
DELETE | /plans/{plan_id} | Delete a plan. |
POST | /plans/{plan_id}/run | Enqueue the whole plan as one ordered pass → { run_ids }. |
Issues (built-in tracker)
| Method | Path | Description |
|---|---|---|
GET | /issues?status= | List native issues (paginated; optional status, q). |
GET | /issues/{id} | Issue detail ({ …, body_md, comments }). |
PATCH | /issues/{id} | Partial edit — any of { status, title, body_md, severity }. status is open / closed / acknowledged. |
POST | /issues/{id}/comments | Add a comment — body { body }. |
Settings (admin)
Writing settings requires an admin.
| Method | Path | Description |
|---|---|---|
GET | /settings | Integration settings — secrets are masked on read. |
PUT | /settings | Save settings — body is the settings object (only non-null fields are written). |
POST | /settings/test-notification | Send a test Slack/Teams notification with the current config. |
Integrations
| Method | Path | Description |
|---|---|---|
GET | /integrations/trackers | Which issue trackers are configured: { github, gitlab, jira } booleans. Drives the dashboard's tracker picker so it only offers what's set up. |
Artifacts
| Method | Path | Description |
|---|---|---|
GET | /artifacts/{path} | A run artifact (per-step screenshot, report). Authenticated — send the Bearer token, or ?token=<jwt> for <img>/<a> tags. Confined to the artifacts directory. |
Generate (anything → suite)
Generate a suite from a live app, your docs/spec, or a description. Exhaustive by default — a multi-pass generator (discover areas → expand each into happy-path, validation, edge, error, auth and negative scenarios in parallel).
| Method | Path | Description |
|---|---|---|
POST | /generate | Body { kind, url?, base_url?, text?, auth?, exhaustive?, save_as? }. kind is url | docs | text | openapi. For url, pass url (a deep page works; add auth: { username, password, login_path? } to reach pages behind login). For docs/text/openapi, pass base_url (what the suite targets) plus a url to fetch or pasted text. Returns { yaml } (plus saved_as). See generation. |
POST | /generate/plan | Exhaustive generation that splits the app into several suites and saves them as a ready-to-run plan. Returns { plan_id, plan_name, suites }. |
Analytics
| Method | Path | Description |
|---|---|---|
GET | /analytics | Flake / run analytics over the full run history. See Flakiness analytics. |
Record (clicks → suite)
A one-click recorder: open a real browser, click through a flow, and we capture it. (Or convert a trace you already have.)
| Method | Path | Description |
|---|---|---|
POST | /record/start | Body { base_url }. Opens a real (headed) browser at base_url and starts capturing clicks/typing/navigation. Returns { record_id }. Requires a desktop session on the API host. |
GET | /record/sessions/{id} | Live status — { status, action_count, base_url, error }. |
POST | /record/stop | Body { record_id, title?, save_as?, humanize? }. Stops the session, converts the captured trace to a suite. Returns { yaml, actions } (plus saved_as). |
POST | /record/convert | Body { actions, base_url, title?, save_as?, humanize? }. Convert an action trace ({ type, selector?, value?, url?, text? }[]) you already have. humanize (default true) uses the LLM to phrase steps. See Record from clicks. |
Checks (standalone)
Dry-run a single deterministic check core without authoring a whole suite. These are not suite expect kinds (suites use the four check kinds) — they are standalone endpoints for dashboards and visual baselines.
| Method | Path | Description |
|---|---|---|
POST | /checks/api | Body { url, method?, status?, json_path?, equals?, headers?, body? }. Runs an HTTP request and asserts status and/or a JSON path. Returns { kind: "api", status, observed }. |
POST | /checks/screenshot | Body { name, image_b64, tol? }. Compares a PNG against the stored baseline for name (first run for a name seeds the baseline and passes). Returns { kind: "screenshot_region", status, observed }. |
Examples
Start a run:
curl -X POST http://127.0.0.1:8400/api/v1/runs \
-H 'Content-Type: application/json' \
-d '{"suite": "signup-login.tripwire.yaml", "file_issues": "tripwire"}'Poll its status, live events, and report:
curl http://127.0.0.1:8400/api/v1/runs/<run-id>Save (and validate) a suite — the body is JSON { "yaml": "..." }:
curl -X PUT http://127.0.0.1:8400/api/v1/suites/signup-login.tripwire.yaml \
-H 'Content-Type: application/json' \
-d "{\"yaml\": $(jq -Rs . < signup-login.tripwire.yaml)}"Generate a suite from a URL and save it:
curl -X POST http://127.0.0.1:8400/api/v1/generate \
-H 'Content-Type: application/json' \
-d '{"url": "https://app.example.com", "save_as": "app-flows"}'Export a suite to portable Playwright:
curl http://127.0.0.1:8400/api/v1/suites/signup-login.tripwire.yaml/export -o tests/signup.spec.tsList open issues from the built-in tracker:
curl 'http://127.0.0.1:8400/api/v1/issues?status=open'Error shape
Errors are returned as JSON via the app's error handlers — e.g. a missing/invalid token returns 401; an action needing admin returns 403; invalid YAML on PUT /suites/{name} returns 400 with a type of invalid_yaml; generation failures return 502 (generation_error).
See also
- Writing tests — the YAML you
PUTto/suites. - Runs & assertions — what
/runs/{id}reports. - Filing issues — the
/issuesand/settingssurface. - CLI · Settings & env.