API Reference

The LetsCompl.ai gateway exposes a REST API for evaluating a JSON payload against a workspace's active rulesets.

Evaluation endpoint

POST https://api.letscompl.ai/api/v1/evaluate

Headers

  • Authorization: Bearer <YOUR_API_KEY> (required)
  • Content-Type: application/json (required)

Request body fields

  • payload (object, required): the JSON action payload or tool-invocation arguments to evaluate.
  • rules (array of strings, optional): restrict evaluation to this subset of rule keys instead of the workspace's full active policy. Omit to evaluate every active rule.
  • pinnedVersions (object, optional): maps a rule key to a historical ruleset version number, for replaying a past policy decision instead of the currently enforced one.

The API does not redact the payload for you — redaction is a client-side feature of the SDKs (@letscomplai/sdk, letscomplai), which redact locally before the request is sent. If you call this endpoint directly (e.g. from curl or a language without an SDK), any PII/PHI you include in payload is sent as-is; redact it yourself first if needed.

Example request

BASHCode Block
curl -X POST https://api.letscompl.ai/api/v1/evaluate \
  -H "Authorization: Bearer lc_live_8832a8..." \
  -H "Content-Type: application/json" \
  -d '{
    "payload": {
      "action": "wire_transfer",
      "amount": 25000,
      "recipient": "sanctioned-co"
    }
  }'

Response fields

  • verdict: "approved", "blocked", or "error". What your code should do.
  • policyVerdict: what the policy actually decided, independent of enforcement mode.
  • enforcement: the mode in effect for this call: ENFORCE or MONITOR.
  • citation: present — { ruleId, ruleName, regulation, bundleRevision?, controlMappings? } — whenever policyVerdict is blocked, regardless of verdict (see "Enforcement mode" below); null otherwise.
  • redactedPayload: the payload actually evaluated, with any PII/PHI tokens already applied by the caller. This is also the payload persisted to EvaluationEvent — see Data Handling for what is and isn't detected.
  • evaluations: per-rule results (pass, redact, flag, unsupported, or block, each with the rule key and, for block, the citation).
  • unsupportedRules: rule keys that are active but have no registered evaluator; these are skipped, not blocked.
  • policyScope: "full" when every active rule ran, "filtered" when the request's rules field restricted evaluation to a subset. A "filtered" response must never be treated as a complete compliance decision.
  • evaluatedRules: the rule keys that actually ran, matching policyScope.
  • pinnedVersions: echoes back only the pins that were actually applied — a pin for a rule excluded by the rules filter is dropped from both evaluation and this echo.
  • latencyMs, llmUsed, piiRedacted, bundleRevision, dataAsOf, sdnDataAgeMs: supporting metadata: total evaluation latency, whether an LLM annotation step ran, whether the submitted payload had redaction tokens, the policy bundle revision, and sanctions-list freshness data where relevant.
  • disclaimer: the exact LEGAL_DISCLAIMER string from lib/engine/disclaimer.ts, present on every response.
  • error: present only when policyVerdict is "error" (e.g. a stale sanctions data source), describing why no policy decision could be produced. Under MONITOR, verdict still reports "approved" in this case — see "Evaluation failures under monitor mode" below.

Enforcement mode

Every evaluation response carries three related fields:

| Field | Meaning |

|---|---|

| verdict | What your code should do: approved, blocked, or error. |

| policyVerdict | What the policy actually decided, independent of enforcement mode. |

| enforcement | The mode in effect for this call: ENFORCE or MONITOR. |

Under ENFORCE, verdict and policyVerdict are always identical.

In monitor mode, a blocking policy verdict does not stop your action: verdict

is approved while policyVerdict is blocked. The evaluation, citation, and

audit record are produced exactly as they would be under enforcement.

**Check policyVerdict, not verdict, when you want to know what your policy

decided.** A monitor-mode response with verdict: "approved" does not mean the

payload passed your rules. This applies whether you're calling this endpoint

directly or through an SDK — the raw response shape is the same either way.

Calling this endpoint directly means there is no guardAction/guard_action

wrapper making the unavailable/deny decision for you. If the request never

reaches the gateway (network failure, timeout, DNS failure), you receive no

response at all and must decide your own fail-open/fail-closed behavior — see

Client Availability and Failure Behavior

for the same availability and quota (429) limitations that apply at this layer.

Example blocked response

JSONCode Block
{
  "verdict": "blocked",
  "policyVerdict": "blocked",
  "enforcement": "ENFORCE",
  "citation": {
    "ruleId": "sanctions_keyword",
    "ruleName": "Sanctions Keyword Block",
    "regulation": "31 CFR Chapter V - OFAC Sanctions Regulations"
  },
  "redactedPayload": {
    "action": "wire_transfer",
    "amount": 25000,
    "recipient": "sanctioned-co"
  },
  "evaluations": [
    {
      "rule": "sanctions_keyword",
      "result": "block",
      "citation": {
        "ruleId": "sanctions_keyword",
        "ruleName": "Sanctions Keyword Block",
        "regulation": "31 CFR Chapter V - OFAC Sanctions Regulations"
      }
    }
  ],
  "unsupportedRules": [],
  "policyScope": "full",
  "evaluatedRules": ["sanctions_keyword"],
  "disclaimer": "LetsCompl.ai is a technical enforcement tool, not a legal compliance service. Verdicts do not constitute legal advice."
}

Example approved response

JSONCode Block
{
  "verdict": "approved",
  "policyVerdict": "approved",
  "enforcement": "ENFORCE",
  "citation": null,
  "redactedPayload": { "action": "payout", "amount": 250 },
  "evaluations": [{ "rule": "ftc_budget_cap", "result": "pass" }],
  "unsupportedRules": [],
  "policyScope": "full",
  "evaluatedRules": ["ftc_budget_cap"],
  "disclaimer": "LetsCompl.ai is a technical enforcement tool, not a legal compliance service. Verdicts do not constitute legal advice."
}

Example monitor-mode response

This request hit a workspace (or API key) configured for MONITOR. The policy

would have blocked the same sanctions_keyword rule as the first example —

policyVerdict says so — but verdict reports approved so the caller's

action proceeds. The citation and audit record are identical to what ENFORCE

would have produced.

JSONCode Block
{
  "verdict": "approved",
  "policyVerdict": "blocked",
  "enforcement": "MONITOR",
  "citation": {
    "ruleId": "sanctions_keyword",
    "ruleName": "Sanctions Keyword Block",
    "regulation": "31 CFR Chapter V - OFAC Sanctions Regulations"
  },
  "redactedPayload": {
    "action": "wire_transfer",
    "amount": 25000,
    "recipient": "sanctioned-co"
  },
  "evaluations": [
    {
      "rule": "sanctions_keyword",
      "result": "block",
      "citation": {
        "ruleId": "sanctions_keyword",
        "ruleName": "Sanctions Keyword Block",
        "regulation": "31 CFR Chapter V - OFAC Sanctions Regulations"
      }
    }
  ],
  "unsupportedRules": [],
  "policyScope": "full",
  "evaluatedRules": ["sanctions_keyword"],
  "disclaimer": "LetsCompl.ai is a technical enforcement tool, not a legal compliance service. Verdicts do not constitute legal advice."
}

Evaluation failures under monitor mode

A blocked policy decision (above) is not the only way policyVerdict can differ

from verdict. If a rule requires data the gateway could not obtain — for

example a sanctions_keyword rule with useSdnList: true when the underlying

sanctions list is missing or stale — the policy never reaches a decision at

all. This is reported as policyVerdict: "error", with an error field

naming the reason (e.g. sanctions_data_unavailable).

Under ENFORCE, this still fails closed: verdict is also "error", and the

caller's action does not proceed. Under MONITOR, the same non-blocking

contract applies as for a policy block: verdict reports "approved" and

the action proceeds, because monitor mode suppresses policy blocks — but a

policy that never ran is not a policy that approved, so the gateway records

evidence of the gap separately from the normal evaluation audit trail. It

persists a workspace-scoped EvaluationFailureEvent (reason, source,

enforcement mode, timestamp, and a bounded rule/data-freshness context — never

the request payload) and, on GROWTH/ENTERPRISE plans with webhooks

configured, dispatches a distinct EVALUATION_UNAVAILABLE alert (never

COMPLIANCE_BLOCK — the two are never the same event). This record exists

precisely so a monitor-mode customer is not left with no evidence that a

sanctions-related rule failed to run.

This response is produced before the engine runs at all — there is no redacted payload to

return and no set of rules that actually evaluated, unlike every other example on this page:

JSONCode Block
{
  "verdict": "approved",
  "policyVerdict": "error",
  "enforcement": "MONITOR",
  "citation": null,
  "redactedPayload": {},
  "evaluations": [],
  "unsupportedRules": [],
  "policyScope": "full",
  "evaluatedRules": [],
  "error": "sanctions_data_unavailable",
  "disclaimer": "LetsCompl.ai is a technical enforcement tool, not a legal compliance service. Verdicts do not constitute legal advice."
}

Legal disclaimer

Every response includes the exact LEGAL_DISCLAIMER string defined in lib/engine/disclaimer.ts. Do not paraphrase or duplicate it elsewhere — reference the field.