HTTP API

Enable the REST + SSE API with relay-core-cli run --api-port 8082. Default base URL: http://127.0.0.1:8082/api/v1/. Add --api-token <T> to require Authorization: Bearer <T> on every request, and --api-cors <origins> to allow browser clients. CORS is only emitted when --api-cors is set; the server is otherwise strict.

Version & Status

GET /api/v1/version

Engine version, API version, and a list of registered capability names.

{
  "engine_version": "0.6.0",
  "api_version": "1",
  "capabilities": ["flows", "rules", "intercepts", "mock", "metrics", "status", "events", "scripts"]
}

GET /api/v1/status

Runtime lifecycle snapshot — uptime, current rules count, intercepts pending, etc.

Flows

GET /api/v1/flows

Search and paginate captured flows. All parameters are optional.

GET /api/v1/flows?method=GET&host=api.example.com&limit=10&offset=0

Query Parameters:

  • host, path, path_contains, method — substring matches
  • status_min, status_max — status code range
  • has_error — only flows with errors
  • is_websocket — only WebSocket flows
  • limit — page size, default 50, clamped to 1–200
  • offset — pagination offset
{
  "items": [{ "id": "fld_...", "method": "GET", "path": "/users", "status": 200 }],
  "returned": 10,
  "limit": 50,
  "offset": 0
}

Redaction is applied to URLs (sensitive query keys) and headers before the response leaves the server, so secrets never appear in the result even if they were observed in traffic.

GET /api/v1/flows/:id

Full Flow JSON including headers and bodies. The same redaction rules apply.

POST /api/v1/flows/:id/replay

Replay a captured flow against the live network. Send a JSON body with optional modifications. ?accept_invalid_certs=true skips TLS verification for the replay (debug only).

GET /api/v1/flows/:id/har

Export a single flow as a HAR 1.2 entry.

GET /api/v1/flows/export/har

Batch HAR export. Accepts the same query parameters as GET /api/v1/flows.

Rules

GET /api/v1/rules

List all interception rules. Each entry contains the full Rule object (id, name, priority, stage, filter, actions, enabled).

GET /api/v1/rules

PUT /api/v1/rules

Create or replace a rule by id.

PUT /api/v1/rules
{
  "id": "rul_01HX5K9P3Q8Y2Z7",
  "name": "Log API requests",
  "priority": 100,
  "filter": {
    "method": "GET",
    "host": "*.example.com",
    "path": "/api/*"
  },
  "action": {
    "type": "log"
  },
  "enabled": true
}

DELETE /api/v1/rules/:id

Delete a rule.

DELETE /api/v1/rules/rul_01HX5K9P3Q8Y2Z7

POST /api/v1/mock

Quickly create a MockResponse rule. Body fields: url_pattern, status, body, content_type.

Intercepts

POST /api/v1/intercepts

Create a one-shot intercept breakpoint.

{
  "url_pattern": "api.example.com",
  "phase": "request"
}

The response includes the generated rule_id used to refer to the intercept.

GET /api/v1/intercepts

List pending intercepts (both HTTP and WebSocket).

POST /api/v1/intercepts/:key/resume

Resume an intercepted flow. Body accepts action (continue or drop) and any FlowModification fields to apply before forwarding: method, url, request_headers, request_body, status_code, response_headers, response_body, message_content.

Policy & Redaction

GET /api/v1/policy

Return the current ProxyPolicy, including the redaction block and (if configured) the upstream block. The password field of an upstream auth is masked as ***.

PATCH /api/v1/policy

Apply a partial update. Both top-level keys are optional:

{
  "redaction": {
    "enabled": true,
    "redact_bodies": true,
    "sensitive_header_names": ["authorization", "x-api-key", "cookie"],
    "sensitive_query_keys": ["token", "api_key", "password"]
  },
  "upstream": {
    "proxy_url": "http://corp-proxy.internal:8080",
    "bypass_hosts": ["*.internal", "127.0.0.1"],
    "fail_open": false
  }
}

Default sensitive header names: authorization, proxy-authorization, cookie, set-cookie, x-api-key, x-auth-token.

Default sensitive query keys: token, access_token, refresh_token, api_key, apikey, password, secret.

Redaction is applied to the HTTP request/response, the WebSocket handshake, every WebSocket message, flow summaries, search results, and the SSE event stream. Changing upstream.proxy_url at runtime returns 409 Conflict — restart the proxy to apply it.

Scripting

POST /api/v1/script

Hot-load a script into the running engine.

{ "script": "// deno-fmt-ignore\nexport default { onRequest(ctx) { /* ... */ } }" }

Events

GET /api/v1/events

Server-Sent Events stream of live updates.

GET /api/v1/events

Event types:

  • flow — new or updated flow (full Flow JSON in the data field)
  • ws-message — new WebSocket message
  • http-body — body chunk available; the data field is { "flow_id": "..." }, fetch the body via GET /api/v1/flows/:id
  • body-budget-exceeded — body cap reached, no further body will be sent
  • audit — control-plane mutation (rule change, intercept resolved, script reloaded, policy updated)
  • audit-lagged — audit channel dropped events, server resyncs
  • lagged — flow / events channel dropped events, TUI resyncs
  • lifecycle — proxy start / stop / reload

Metrics

GET /api/v1/metrics

JSON metrics snapshot. Same fields as relay-core-cli metrics (see CLI reference).

GET /api/v1/metrics/prometheus

Prometheus text format metrics.

# HELP relay_core_flows_total Total number of flows captured
# TYPE relay_core_flows_total counter
relay_core_flows_total 12847

# HELP relay_core_request_duration_ms Request duration in milliseconds
# TYPE relay_core_request_duration_ms histogram
relay_core_request_duration_ms_bucket{le="1"} 10023
relay_core_request_duration_ms_bucket{le="5"} 12500
relay_core_request_duration_ms_bucket{le="10"} 12800
relay_core_request_duration_ms_bucket{le="+Inf"} 12847

Script-engine metrics are emitted per hook: relay_core_script_hook_duration_us{hook}, relay_core_script_hook_invocations_total{hook}, relay_core_script_hook_errors_total{hook}, plus relay_core_script_env_access_total, relay_core_script_fetch_total, and relay_core_script_fetch_rejected_total.

Audit

GET /api/v1/audit

Query the control-plane mutation audit log.

GET /api/v1/audit?since_ms=1705276800000&actor=http&kind=policy_updated

Query Parameters:

  • since_ms, until_ms — epoch milliseconds; either may be omitted
  • actorruntime, http, tauri, probe, or cli
  • kindrule_changed, intercept_resolved, script_reloaded, policy_updated
  • outcomesuccess or failure

The response is a JSON array of AuditEvent entries. Each event records who made the change, when, and the relevant before/after diff for mutations.