/recall/*, with the versioned audit-log read at /v1/recall/audit-log. The base URL is https://api.visiqlabs.com.
Action governance and retrieval governance share a single rule engine — each rule declares which facets it applies to. The endpoints on this page are the retrieval facet: they govern what your agents can see (retrieved documents, tool results, rendered prompts), with decisions allow, deny, redact, and escalate.
Authentication
All endpoints require a Bearer credential:Authorization: Bearer <key>. Requests without a valid credential receive 401 Unauthorized.
Two credential audiences exist:
- Harness keys — the operational credential your SDK or harness runs with. Either a
vq_prod_.../vq_test_...key minted in the dashboard under Settings → Harness Keys, or theallow_...key returned once byPOST /allow/agents. On the retrieval surface the operational allowlist covers exactlyPOST /recall/evaluateandGET /recall/rules/bundle— calling any other endpoint on this page with a harness key returns403 {"error": "harness_key_not_permitted"}. - Management keys — general automation credentials governed by explicit permission grants. They can call every endpoint on this page. Management keys are launching soon: they are visible in the dashboard under Settings → API Keys, but creating one is not yet enabled. Until then, drive the management endpoints from the dashboard, which authenticates with your session.
rules:evaluate (or the legacy recall:write); reads require rules:read (or the legacy recall:read); rule mutations require rules:write (or the legacy recall:write); full_access satisfies everything. A key without the required scope receives 403 {"error": "insufficient_scope"} listing the required and granted scopes.
Rate limiting
Every API-key request passes a per-key sliding-window rate limit (default 600 requests per 60 seconds). Responses carryX-RateLimit-Limit and X-RateLimit-Remaining headers; exceeding the window returns 429 with a Retry-After header and body {"error": "rate_limited", "detail": "API key rate limit exceeded.", "retryAfter": <seconds>}.
List responses
Every list endpoint on this page returns the same envelope:page (default 1) and limit (default 50, max 100) query parameters.
Evaluation
The endpoints your SDK or harness calls at runtime. Both accept a harness key. The SDK evaluates most retrievals locally from the cached rule bundle — the server and the SDK run the same policy interpreter over the same rule source, so local and remote decisions agree by construction.POST /recall/evaluate
Evaluate a retrieval against your suppression rules and return a decision. Scope:rules:evaluate or recall:write
Request body:
Agent attributes are server-authoritative. The platform looks up
agent_id in the agent registry and hydrates its assigned trust tier, categories, and business function into rule input (input.agent.*). An assigned trust tier overrides the request’s trust_tier — the body value is only a fallback for agents with no assigned tier, so varying it in a request cannot spoof a tier-gated rule. Unlike the action facet’s evaluate endpoint, this endpoint does not auto-provision unknown agents.For an agent in monitor mode, a non-allow decision is normalized to
allow before it is recorded and returned, with reason_code: "MONITOR_MODE" and the engine’s original reason preserved behind a Monitor: prefix.
Decision semantics:
allow— the content passes to the agent unchanged.deny— the content is suppressed; the agent never sees it.redact— the content proceeds with the accompanyingredaction_rulesapplied.escalate— hold the content for human review; if no human approves in time, fall back perhitl_fallback.
redaction_rules may include field, pattern, replacement, mode (full | partial | email | custom), keepFirst, keepLast, maskChar, and keepPattern. full replaces the whole match (the default); partial keeps the first/last characters; email keeps the first character of the local part plus the domain; custom keeps every keepPattern match and masks the rest. A redact decision from a rule whose directives resolve to nothing passes content through unchanged — unless the rule is flagged fail-closed, in which case the decision is downgraded to deny server-side.
The escalate decision tells your harness to hold the content for human review — this endpoint does not itself notify approvers; register the approval through the human-in-the-loop flow (see Human-in-the-Loop). hitl_fallback tells the harness what to do when no human responds in time: deny (the default, fail-closed) or mask (proceed with the accompanying redaction_rules applied).
Reason codes:
The response carries no receipt ID — tamper evidence is asynchronous. For organizations with artifact signing enabled, each decision emits a record envelope that receives an Ed25519 receipt off the request path, is Merkle-batched under a KMS-signed root with an RFC 3161 timestamp, and lands in a hash-chained checkpoint log. Verify a decision’s record envelope server-side via
GET /record/envelopes/:id/verify (:id is the record envelope’s UUID, not the decision_id returned here).Minimum-necessary at rest: the decision is evaluated against the real values, but the persisted copies of
resource_metadata and query are masked — first by the matched rule’s redaction directives, then by an always-on value-shape redaction floor. The raw original is discarded by default; organizations can opt in to retaining it encrypted, revealable only via the retained-original endpoint.200 OK, 400 Bad Request, 401 Unauthorized, 403 Forbidden (insufficient scope), 429 Too Many Requests, 500 Internal Server Error
Example:
GET /recall/rules/bundle
Fetch your enabled retrieval rules as one bundle for local evaluation. Clients can cache this bundle and revalidate it withIf-None-Match, so retrieval decisions on the hot path never wait on the network. (The VisIQ SDK consumes the unified GET /rules/bundle, which carries both facets.)
Request headers:
Response:
Response headers:
Status codes:
200 OK, 304 Not Modified, 401 Unauthorized, 403 Forbidden (insufficient scope), 500 Internal Server Error
Rules
Rule management. These are management endpoints — a harness key receives403 harness_key_not_permitted here. The recommended authoring path is the dashboard’s rule editor (natural-language compile, visual condition builder, and a Simulate panel that checks a new rule against your recent traffic — rules projected to inhibit more than 5% of it are blocked). These endpoints are the programmatic equivalent.
GET /recall/rules
List retrieval rules, sorted by priority descending — the same order the engine evaluates them in (first match wins). Query parameters:page (default 1), limit (default 50, max 100)
Response:
rego_source; fetch a single rule to read the policy source.
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 500 Internal Server Error
POST /recall/rules
Create a retrieval rule. Request body:rego_source holds the rule’s policy source in the platform’s Rego-subset condition language (equality, inequality, set membership, startswith/endswith/contains, regex, counts, and numeric comparisons). The decision (allow, deny, redact, escalate) is derived from the policy body. Prefer POST /recall/rules/compile — the compiler drafts and validates the policy against the live evaluation engine.rego_source.
Status codes: 201 Created, 400 Bad Request, 401 Unauthorized, 500 Internal Server Error
POST /recall/rules/compile
Compile a natural-language description into a retrieval rule. The compiler reads your existing rules for context, drafts the policy source, and validates it against the live evaluation engine. Rate limit: 10 compile requests per minute per organization — exceeding it returns429.
Query parameters: stream=true — stream the compile over Server-Sent Events instead of a single JSON response (also triggered by Accept: text/event-stream).
Request body:
Response:
?stream=true): a text/event-stream of JSON events —
{"type":"error","message":"..."} and closes.
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 422 Unprocessable Entity (the compiler could not produce a valid policy — refine the prompt), 429 Too Many Requests, 500 Internal Server Error, 503 Service Unavailable (rule compilation is not configured in this environment)
GET /recall/rules/:id
Get a single rule by UUID, includingrego_source.
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error
PUT /recall/rules/:id
Update a rule. Same fields asPOST /recall/rules, all optional; at least one is required. Only provided fields change. trust_tier, surface, and principal_exclusions accept null to clear.
Response: the updated rule object.
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error
DELETE /recall/rules/:id
Delete a rule permanently. Response:{ "deleted": true }
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error
Emergency Bypass
Temporarily suspend one rule’s enforcement during an incident — see Emergency Bypass for when and why. Bypasses auto-expire; expiry is checked at evaluation time, so there is no revocation lag. Both activation and deactivation are written to the audit log with reason codeEMERGENCY_BYPASS.
POST /recall/rules/:id/bypass
Activate an emergency bypass on a rule. While active, any request that reaches the bypassed rule in the priority cascade returnsallow with reason code EMERGENCY_BYPASS — even requests the rule’s conditions would not have matched — and lower-priority rules never run for it. Higher-priority rules keep enforcing.
Request body:
Response: the full rule object with the bypass fields populated:
200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 409 Conflict (a bypass is already active on this rule), 500 Internal Server Error
DELETE /recall/rules/:id/bypass
Deactivate an active bypass before it expires. Response: the full rule object with the bypass fields cleared. Status codes:200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 409 Conflict (no active bypass on this rule), 500 Internal Server Error
Audit Log
GET /v1/recall/audit-log
Query the retrieval decision audit log. Every decision made through this endpoint — allow and deny, including monitor-mode observations and bypass activations — is recorded. (Locally evaluated SDK decisions surface through the runtime telemetry pipeline instead.) The log is append-only; no writes are accepted via this API.Tamper evidence comes from the signed record pipeline, not from the query API: for organizations with artifact signing enabled, each decision emits a record envelope that receives an asynchronous Ed25519 receipt, is Merkle-batched under a KMS-signed root with an RFC 3161 timestamp, and lands in a hash-chained checkpoint log. Verify a decision’s record envelope server-side via
GET /record/envelopes/:id/verify.rules:read or recall:read (management keys / dashboard session — harness keys cannot query the log)
Query parameters:
Rows recorded under monitor mode carry
reason_code: "MONITOR_MODE"; it is not yet accepted as a filter value.
Response:
metadata.query and metadata.resource_metadata are the masked persisted copies (rule directives plus the always-on redaction floor); metadata.floor_detectors names any floor detectors that fired, and metadata.decision_id is the underlying decision’s ID for the retained-original reveal below. receipt_id is a legacy column and is null on new rows — receipts flow through the record pipeline instead.
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 403 Forbidden (insufficient scope), 429 Too Many Requests, 500 Internal Server Error
Retained Originals
GET /recall/decisions/:id/unmask
Reveal the retained, encrypted original payload for one retrieval decision. Persisted copies are masked at rest; when your organization has enabled retained-original storage (off by default), the rawresource_metadata and query are additionally stored AES-256-GCM-encrypted, and this endpoint decrypts them.
This is a management endpoint gated on the payloads:unmask permission — only explicitly-authorized roles can ever see the original values, and every reveal is logged with who requested it. Harness keys receive 403.
Path parameter: :id — the decision UUID (decision_id from POST /recall/evaluate, or metadata.decision_id on an audit-log row)
Response:
200 OK, 400 Bad Request (invalid UUID), 401 Unauthorized, 403 Forbidden, 404 Not Found (unknown decision, or retention is disabled for your organization), 500 Internal Server Error