SDK Integration
The LetsCompl.ai SDKs (@letscomplai/sdk for TypeScript/JavaScript, letscomplai for Python) redact PII/PHI locally before any network call, then submit the redacted payload to the LetsCompl.ai evaluation gateway (https://api.letscompl.ai) for a compliance verdict against your workspace's active rulesets.
Installation
# npm
npm install @letscomplai/sdk
# pip
pip install letscomplaiTypeScript / JavaScript
import { LetsComplaiClient } from "@letscomplai/sdk";
const client = new LetsComplaiClient({
apiKey: process.env.LETSCOMPLAI_API_KEY!,
});
const result = await client.evaluate({
patientName: "John Doe",
mrn: "MRN-12345",
diagnosis: "Acute bronchitis",
amount: 250,
});
console.log(result.verdict); // "approved" | "blocked" | "error"
console.log(result.redactedPayload);
/*
{
patientName: "[REDACTED_NAME]",
mrn: "[REDACTED_MRN]",
diagnosis: "Acute bronchitis",
amount: 250
}
*/evaluate() redacts locally before sending anything over the network — values matching our recognized patterns never leave your process unless you pass redact: false as an explicit opt-out. Redaction is pattern-based, not exhaustive; see Data Handling for full coverage and known gaps. If you only need local redaction with no network call, use client.redactLocal(payload) or the standalone redact() export.
Guarding an action
guardAction wraps a payload check and the action it gates in one call: it throws ComplianceBlockedError if the verdict is blocked, and (by default) ComplianceUnavailableError if the gateway is unreachable, before your action runs.
import { LetsComplaiClient } from "@letscomplai/sdk";
const client = new LetsComplaiClient({
apiKey: process.env.LETSCOMPLAI_API_KEY!,
});
const result = await client.guardAction(
{ action: "payout", amount: 1200 },
() => payments.createPayout({ amount: 1200 }),
);Python
from letscomplai import LetsComplaiClient
client = LetsComplaiClient(api_key="your-api-key")
result = client.evaluate({
"patient_notes": "Mr. John Smith has a history of asthma.",
})
print(result["verdict"]) # "approved" | "blocked" | "error"An async client mirrors the same methods for asyncio applications:
from letscomplai import AsyncLetsComplaiClient
client = AsyncLetsComplaiClient(api_key="your-api-key")
result = await client.evaluate({"action": "payout", "amount": 1200})
await client.aclose()Both clients expose guard_action(payload, action, ...), which raises ComplianceBlockedError/ComplianceUnavailableError the same way the TypeScript SDK does.
Full reference
See docs/user/api-reference.md for the request/response schema, verdict values, and policyScope/evaluatedRules/pinnedVersions behavior — the SDKs are thin clients over that same contract.
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. For example, a workspace configured for MONITOR
whose policy would have blocked the payload returns:
{ "verdict": "approved", "policyVerdict": "blocked", "enforcement": "MONITOR" }For timeout, fail-open/fail-closed, retry, SLA, and local-enforcement behavior, see docs/operations/client-availability.md.
LEGAL_DISCLAIMER (lib/engine/disclaimer.ts): "LetsCompl.ai is a technical enforcement tool, not a legal compliance service. Verdicts do not constitute legal advice." Every gateway response's disclaimer field carries this exact text; the SDK-fabricated error envelope returned when a request never reaches the gateway (transport/timeout failures) does not populate it.