Decision API

Fairvisor Edge exposes a minimal HTTP API on port 8080.

Endpoints

Endpoint Method Purpose
/v1/decision POST Evaluate a request against the active policy bundle
/v1/debug/session POST Start per-user debug session (when debug secret is configured)
/v1/debug/logout POST End per-user debug session
/livez GET Liveness probe — always returns 200 ok
/readyz GET Readiness probe — 200 ok if a bundle is loaded
/metrics GET Prometheus metrics

POST /v1/decision

The primary endpoint. Evaluates the incoming request headers against the active policy bundle and returns 200 (allow) or 429 (reject).

Request

Header Required Description
X-Original-Method Yes HTTP method of the original request (GET, POST, …)
X-Original-URI Yes Full URI of the original request, including query string
X-Original-Host Conditionally Original request host. Required when using selector hosts.
Authorization No Bearer JWT; used for jwt:<claim> descriptor keys
X-Forwarded-For No Client IP chain; used for ip:address and ip:country keys
X-ASN-Type No Optional fallback input for ip:type when set by gateway/proxy
X-Tor-Exit No Optional override for ip:tor (1/0, true/false, yes/no)
Any custom header No Used when a policy references header:<name> limit keys

The request body is not consumed.

Response: 200 Allow

HTTP/1.1 200 OK
RateLimit-Limit: 1000
RateLimit-Remaining: 847
RateLimit-Reset: 1
RateLimit: "per-org-rps";r=847;t=1

Body is not part of the public contract (current implementation returns empty body on allow).

Response: 429 Reject

HTTP/1.1 429 Too Many Requests
Retry-After: 15
X-Fairvisor-Reason: token_bucket_exceeded
RateLimit-Limit: 1000
RateLimit-Remaining: 0
RateLimit-Reset: 15
RateLimit: "api-limits";r=0;t=15

Body: implementation-dependent (do not rely on it).

Debug session headers (optional)

When debug session is active, Fairvisor also returns debug headers such as:

  • X-Fairvisor-Debug-Policy
  • X-Fairvisor-Debug-Rule
  • X-Fairvisor-Debug-Reason

See Debug Session.

Response: 503 No bundle

If no policy bundle is loaded (e.g., immediately after startup before SaaS delivers config):

HTTP/1.1 503 Service Unavailable
X-Fairvisor-Reason: no_bundle_loaded

GET /livez

Always returns 200 while the nginx process is running. Use as a Kubernetes livenessProbe.

HTTP/1.1 200 OK

ok

GET /readyz

Returns 200 when a policy bundle is loaded and the engine is ready to process requests. Returns 503 during startup before the first bundle is applied.

HTTP/1.1 200 OK

{"status":"ready","policy_version":"...","policy_hash":"...","last_config_update":1736940000}
HTTP/1.1 503 Service Unavailable

{"status":"not_ready","reason":"no_policy_loaded"}

Use as a Kubernetes readinessProbe to hold traffic until the edge is ready.


GET /metrics

Returns Prometheus-format metrics.

HTTP/1.1 200 OK
Content-Type: text/plain; version=0.0.4

# HELP fairvisor_decisions_total Total decisions
# TYPE fairvisor_decisions_total counter
fairvisor_decisions_total{action="allow",reason="all_rules_passed",policy="policy-a",route="/api/v1"} 1542
fairvisor_decisions_total{action="reject",reason="token_bucket_exceeded",policy="policy-a",route="/api/v1"} 23
...

See Metrics for the full metric catalogue.


Mode differences

Aspect decision_service reverse_proxy
Host/method/URI source X-Original-Host, X-Original-Method, X-Original-URI nginx $host, $request_method, $uri
Response headers Written directly to the decision response Stored in ngx.ctx; written by header_filter_by_lua_block
Request body handling Not consumed Consumed/forwarded to backend

In reverse_proxy mode, callers do not call /v1/decision directly — Fairvisor Edge acts as a transparent proxy that enforces policy on every proxied request.


Authentication

The decision endpoint itself has no authentication. It is an internal service; expose it only to trusted callers (nginx internal location, Envoy cluster, VPC-internal network). Do not expose port 8080 to the public internet.