# Compliance

URL: https://docs.hanzo.ai/docs/openapi/compliance

> Your KYC/KYB onboarding, accreditation records, and the evidence trail behind them.

Also for this capability: **API** · [CLI](https://docs.hanzo.ai/docs/cli/compliance) · [MCP](https://docs.hanzo.ai/docs/mcp-tools/compliance) · [SDKs](https://docs.hanzo.ai/docs/sdks)

Your KYC/KYB onboarding, accreditation records, and the evidence trail behind them.

> [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|                |                                        |
| -------------- | -------------------------------------- |
| **Base URL**   | `https://api.hanzo.ai`                 |
| **Operations** | 17                                     |
| **Auth**       | `Authorization: Bearer $HANZO_API_KEY` |

## Specification

> **HIP-1115 · Compliance — Verification of Record** — Draft · [read the specification →](https://github.com/hanzoai/hips/blob/7ed737180339cd05b5f2935eafe7f7b83d2449a2/HIPs/hip-1115-compliance.md)

`/v1/compliance` is an org's verification records: subjects (the people and
entities being verified), verification checks and their decisions,
accreditation, and the org-scoped record and audit reads that prove what was
decided and when. It is implemented in `hanzoai/cloud` `apps/compliance`. This
HIP states what the capability owns — a sealed store of subject PII and
decisions — and the two fail-closed seams that keep a verification honest: the
provider and its webhook.

### Motivation

A verification that cannot be replayed is not a compliance record; it is a
checkbox. The record has to survive the provider that produced it, carry the
decision beside the evidence reference, and be readable only by the org it
belongs to — which makes it a store of its own, not a relay to a vendor
dashboard.

### Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted
as in RFC 2119.

#### §1 The store

One SQLite file — the system namespace's `compliance` — born encrypted, so
subject PII (name, email) is encrypted at rest (`apps/compliance/store.go:19-22`).
Tenant isolation is physical in the schema: `org` is a column on every table
and every read and write filters by it; a record belonging to another tenant is
indistinguishable from one that does not exist, so there is no cross-tenant
probe (`apps/compliance/store.go:14-16`).

#### §2 The provider seam, fail-closed

Verification runs through the `idv.Provider` seam: Manual by default, a real
provider when configured — and a named-but-misconfigured provider MUST fail the
mount rather than silently downgrade to Manual
(`apps/compliance/compliance.go:50-64`). The optional provider webhook receiver
is authenticated by signature rather than by a principal, and it follows the
same rule: a named-but-unresolvable secret fails the mount rather than serving
an unauthenticated endpoint; nil means no webhook path is served at all
(`apps/compliance/compliance.go:66-70`).

#### §3 The addresses

Everything is under `/v1/compliance`: `subjects` (create, list, detail),
`verifications` (create, list, detail, `decision`, `refresh`, and the
signature-authenticated `webhook`), `accreditation` (create, list, detail,
`decision`), plus the reads `records`, `status`, `audit` and `health`. The
prefix is written once and composed onto every op
(`apps/compliance/compliance.go:25-29`). Operations are typed
(`apps/compliance/typed_wire_test.go`); the webhook is declared for what it is
— a provider-signed callback, not a principal-authenticated method.

#### §4 Tenancy, money, events, telemetry, stage, upstreams

Every handler resolves the org through `principal.Acting` (HIP-0026)
(`apps/compliance/compliance.go:281`); no principal, no answer. The capability
is METERED (`plugin/compliance/main.go:28`, `Price: cloud.Metered`), and the
billed act is exactly one: starting a verification opens an inquiry at the
provider on the deployment's own key, so the caller's ledger is charged the
inquiry fee — `CLOUD_COMPLIANCE_FEE_CENTS[_INQUIRY]`, resolved through the
fleet's ordinary provision default, authorized BEFORE the provider is asked
and debited only after an inquiry actually opened
(`apps/compliance/meter.go:29-55`). Everything else on the surface reads the
org's own rows and is free. It publishes no events
on the bus. Beyond the request span, compliance-relevant actions are recorded
on the shared audit plane under the `compliance.` action prefix
(`apps/compliance/compliance.go:31-32`), which is how `/v1/compliance/audit`
can answer. Its stage is the one its manifest row declares, which HIP-0139 §8
keeps as the single copy; this text carried `beta` after the row had become
`ga`. It derives from no
upstream; the provider integration is a configuration of the `idv` seam, and
storage is the `hanzoai/sqlite` facade.

### Rationale

Fail-closed at mount, rather than at first use, is the deliberate choice in
both seams. A provider that silently degrades to Manual passes every health
check and quietly stops verifying — the operator finds out during an audit,
which is the most expensive possible moment. Failing the mount converts a
misconfiguration into a deploy failure, which is cheap and immediate.

The alternative to owning a store is relaying to the provider's records. That
couples the org's compliance history to a vendor contract: cancel the vendor,
lose the history. The store keeps the decision and its reference; the provider
keeps the evidence it is contractually the custodian of.

### Security Considerations

This store is PII plus regulatory decisions — the two things with the highest
disclosure cost per row. The wrong implementation leaks a tenant's customer
list with names and emails attached, or lets a forged webhook flip a
verification to approved. The defenses are stated above because they are the
design: encryption at rest, org on every row with not-found aliasing, and a
webhook that either verifies a signature or does not exist. The decision
endpoints are the residual surface: they accept a human judgment, and the
audit trail under the `compliance.` prefix is what makes such a judgment
attributable after the fact.

## Four surfaces

| Surface  | Reaches this capability as                         | Coverage                                                                   |
| -------- | -------------------------------------------------- | -------------------------------------------------------------------------- |
| **REST** | `compliance` at its own prefix                     | 17 operations                                                              |
| **CLI**  | `hanzo compliance …`                               | 17 of 17                                                                   |
| **SDK**  | `ComplianceApi` in every published client          | 17 methods                                                                 |
| **MCP**  | tool `compliance` on `https://api.hanzo.ai/v1/mcp` | 16 operations, 5 under the document's own id — ask `describe` for the rest |

## Quickstart

```bash
export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys
```

Then the first call — a read that needs nothing but the key. `GET /v1/compliance/audit`, operation `get_compliance_audit`:

**CLI**

```bash
hanzo compliance audit
```

**SDK**

**.ts**

```ts
import { Configuration, ComplianceApi } from 'hanzoai';

const api = new ComplianceApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.getComplianceAudit();
```

**.py**

```python
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ComplianceApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ComplianceApi(client).get_compliance_audit()
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.ComplianceAPI.GetComplianceAudit(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::apis::{configuration::Configuration, compliance_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = compliance_api::get_compliance_audit(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ComplianceApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new ComplianceApi(client).getComplianceAudit();
```

**HTTP**

```bash
curl https://api.hanzo.ai/v1/compliance/audit \
  -H "Authorization: Bearer $HANZO_API_KEY"
```

**MCP**

Tool `compliance`, op `get_compliance_audit` — POST the JSON-RPC envelope to `https://api.hanzo.ai/v1/mcp`.

```bash
curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "compliance",
         "arguments": {
           "op": "get_compliance_audit",
           "input": {}
         }
       }
     }'
```

Answers `200` with `object` — ok.

## Endpoints

| Endpoint                                                                                                                                        | What it does                                                                                                                                                                                                         |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`POST /v1/compliance/accreditation/{id}/decision`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-accreditation-by-id-decision) | Records an org reviewer's decision on an accreditation record — a reviewer confirmation, a provider verification the reviewer has evidence of (a CPA/attorney letter, a verifier report), a rejection, or an expiry. |
| [`GET /v1/compliance/accreditation/{id}`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-accreditation-by-id)                     | Returns one tracked accreditation record.                                                                                                                                                                            |
| [`GET /v1/compliance/accreditation`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-accreditation)                                | Returns the org's tracked accreditation-state records, newest first — evidence entries the org keeps, never a platform certification.                                                                                |
| [`POST /v1/compliance/accreditation`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-accreditation)                              | Records an ASSERTED accreditation state for a subject — the subject's own assertion, with no verifier.                                                                                                               |
| [`GET /v1/compliance/audit`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-audit)                                                | The compliance read of the SHARED tamper-evident audit plane — the SOC 2 posture surface (privileged actions: who started/decided what, when).                                                                       |
| [`GET /v1/compliance/health`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-health)                                              | Reports subsystem liveness and the wired verification provider.                                                                                                                                                      |
| [`GET /v1/compliance/records`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-records)                                            | The unified compliance-record view for the org: its verifications and accreditation records together, each provider-reported or tracked, never platform-asserted.                                                    |
| [`GET /v1/compliance/status`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-status)                                              | The org's honest posture read: the wired provider and the per-status tally of its verifications.                                                                                                                     |
| [`GET /v1/compliance/subjects/{id}`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-subjects-by-id)                               | Returns one subject WITH its contact PII — the only surface that returns it, and only to the owning org.                                                                                                             |
| [`GET /v1/compliance/subjects`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-subjects)                                          | Returns the org's subjects as PII-MINIMIZED summaries — no name or email, only whether an email is on file.                                                                                                          |
| [`POST /v1/compliance/subjects`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-subjects)                                        | Records a party the org is verifying as part of its own onboarding/compliance — a team member, vendor, customer, or counterparty.                                                                                    |
| [`POST /v1/compliance/verifications/{id}/decision`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-verifications-by-id-decision) | Records a privileged reviewer's MANUAL decision on a verification — the human-in-the-loop path, and the ONLY route to a passing status when no real provider is wired.                                               |
| [`POST /v1/compliance/verifications/{id}/refresh`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-verifications-by-id-refresh)   | Polls the wired provider for its current decision and records it, ATTRIBUTED to the provider — the internal PULL reconcile.                                                                                          |
| [`GET /v1/compliance/verifications/{id}`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-verifications-by-id)                     | Returns one verification — its opaque subject reference and provider-reported status, no subject PII.                                                                                                                |
| [`POST /v1/compliance/verifications/webhook`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-verifications-webhook)              | Provider push that settles a verification, authenticated by HMAC signature                                                                                                                                           |
| [`GET /v1/compliance/verifications`](https://docs.hanzo.ai/docs/openapi/compliance/get-compliance-verifications)                                | Returns the org's KYC/KYB verifications, newest first — opaque subject references and provider-reported statuses only, no subject PII.                                                                               |
| [`POST /v1/compliance/verifications`](https://docs.hanzo.ai/docs/openapi/compliance/post-compliance-verifications)                              | Begins a KYC/KYB verification of a subject through the wired provider — an existing subject by id, or one created inline from the request.                                                                           |

---

[All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
