# Legal

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

> The paperwork your company needs, drafted, signed and filed.

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

The paperwork your company needs, drafted, signed and filed.

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

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

## Specification

> **HIP-1135 · Legal — Documents Drafted, Signed and Filed** — Draft · [read the specification →](https://github.com/hanzoai/hips/blob/7ed737180339cd05b5f2935eafe7f7b83d2449a2/HIPs/hip-1135-legal-documents.md)

`/v1/legal` is the paperwork an org needs, drafted, signed and filed: a
versioned, org-overridable library of standardized templates, a pure
merge-field engine that renders them from the org's own data, a sealed store
for the generated documents, and the e-signature and filing seams that carry a
document to execution. It is implemented in `hanzoai/cloud` at `apps/legal`
(HIP-0106).

### Motivation

Formation and securities paperwork is templated work over data the platform
already holds — the company record, the cap table. What must never be templated
away is the boundary: the platform manages documents; it does not give legal
advice and does not determine that a document is valid or sufficient. That
boundary is a design invariant enforced in the engine and the data model, not a
disclaimer pasted on a page (`apps/legal/model.go:10-18`).

### Specification

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

#### §1 The store and the renderer

One encrypted SQLite file, the deployment's own `legal`, opened through the one
opener so it is born encrypted (`apps/legal/store.go:30`) — a rendered contract
carries names and terms and is sealed on disk. The renderer is `text/template`
and pure: deterministic, no clock, no I/O, so the same inputs yield identical
bytes and a rendered contract is reproducible (`apps/legal/model.go:20-24`).

#### §2 The boundary in the model

There is no `legally_valid` state: a document is draft, out\_for\_signature,
signed or voided, nothing more. Formation and securities templates carry a
mandatory counsel-review notice the engine prepends to every rendered document —
the platform can never emit such a document without it
(`apps/legal/model.go:13-18`). A disclaimer rides on every generation and
template response.

#### §3 The address

Eleven operations under `/v1/legal`, all typed except one. The exception is
`POST /v1/legal/documents/{id}/sign/complete`, untyped by design: it discards
its decode error so a provider-reported completion still lands when the
callback body is unparseable — the typed layer refuses such a body before the
handler runs, so typing it would turn today's 200 into a 400
(`apps/legal/legal.go:87-91`). The provider's own status is checked first; an
explicit body signal exists for the stub (`apps/legal/legal.go:170-182`). A
1 MiB body cap sits in front of every route, registered before the typed ops
because a size check inside one would run after the parse it exists to precede
(`apps/legal/legal.go:66-77`).

#### §4 The seams fabricate nothing

E-signature and filing are provider-agnostic seams with honest stub defaults: a
seam with no real backend records an honest state and never fakes a completed
signature or a filed record (`apps/legal/providers.go:10-16`). Every generate,
sign and file action is recorded on the shared tamper-evident audit plane,
referencing opaque document ids (`apps/legal/model.go:26-28`).

#### §5 Tenancy, money, events, observability, stage, upstream

The tenant is `principal.Org` off the validated principal (HIP-0026), read back
from what the composer's bridge parked — never a header, never an In field
(`apps/legal/legal.go:156`). Free (`cloud.Free`, `plugin/legal/main.go`). It
publishes nothing on the bus and emits nothing beyond the request span; the
audit records above are the audit plane's, not telemetry. Stage `beta`: a
vertical application. It derives from no upstream — the renderer is the Go
standard library's `text/template` and the templates are authored here.

### Rationale

The alternative to a pure renderer is one that reaches for live data at render
time, which makes a contract unreproducible: the same request on two days
yields two different documents and no record of why. Determinism is what makes
the sealed store an archive rather than a cache. The alternative to honest
stubs is refusing to mount without providers, which would couple a template
library to two vendor contracts nobody needs on day one.

### Security Considerations

A legal store is a disclosure surface — names, terms, equity — so documents are
sealed at rest and the tenant is never an input. The execution path is where a
wrong implementation does real-world harm: a seam that fabricated a "signed" or
"filed" state would manufacture legal evidence, which is why the stubs are
honest and completion consults the provider before any caller-supplied signal.
The completion endpoint is org-scoped and moves only the document's status; it
mints no provider record.

## Four surfaces

| Surface  | Reaches this capability as                    | Coverage                                                                   |
| -------- | --------------------------------------------- | -------------------------------------------------------------------------- |
| **REST** | `legal` at its own prefix                     | 11 operations                                                              |
| **CLI**  | `hanzo legal …`                               | 11 of 11                                                                   |
| **SDK**  | `LegalApi` in every published client          | 11 methods                                                                 |
| **MCP**  | tool `legal` on `https://api.hanzo.ai/v1/mcp` | 10 operations, 1 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/legal/health`, operation `get_legal_health`:

**CLI**

```bash
hanzo legal health
```

**SDK**

**.ts**

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

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

**.py**

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

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

**.go**

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

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

**.rs**

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

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

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

**.java**

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

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

var result = new LegalApi(client).getLegalHealth();
```

**HTTP**

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

**MCP**

Tool `legal`, op `get_legal_health` — 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": "legal",
         "arguments": {
           "op": "get_legal_health",
           "input": {}
         }
       }
     }'
```

Answers `200` with `object` — ok.

## Endpoints

| Endpoint                                                                                                                           | What it does                                                                                                                                                                         |
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`POST /v1/legal/documents/{id}/sign/complete`](https://docs.hanzo.ai/docs/openapi/legal/post-legal-documents-by-id-sign-complete) | Record that a generated document's signature request completed                                                                                                                       |
| [`POST /v1/legal/documents/{id}/sign`](https://docs.hanzo.ai/docs/openapi/legal/post-legal-documents-by-id-sign)                   | Opens an e-signature request over one document and moves it to out\_for\_signature, returning the provider's reference for the request.                                              |
| [`GET /v1/legal/documents/{id}`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-documents-by-id)                               | Returns one of the org's documents WITH its rendered body.                                                                                                                           |
| [`GET /v1/legal/documents`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-documents)                                          | Returns the org's generated documents, newest first, WITHOUT their rendered content — fetch one document to read its body.                                                           |
| [`POST /v1/legal/documents`](https://docs.hanzo.ai/docs/openapi/legal/post-legal-documents)                                        | Renders a document from a template and the caller's own merge data, seals it in the org's store, and returns it with its rendered body.                                              |
| [`GET /v1/legal/filings`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-filings)                                              | Returns the org's filing records, newest first — which documents were filed where, through which provider, and what the filing's honest status is.                                   |
| [`POST /v1/legal/filings`](https://docs.hanzo.ai/docs/openapi/legal/post-legal-filings)                                            | Records a filing of one or more of the org's documents with a state or agency, and returns the tracking record.                                                                      |
| [`GET /v1/legal/health`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-health)                                                | Reports that the legal subsystem is serving and how many built-in templates its catalog carries.                                                                                     |
| [`GET /v1/legal/templates/{id}`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-templates-by-id)                               | Returns one template resolved for the caller's org — the org's own override if it has saved one, else the built-in — with its full text/template body and its declared merge fields. |
| [`PUT /v1/legal/templates/{id}`](https://docs.hanzo.ai/docs/openapi/legal/put-legal-templates-by-id)                               | Saves the org's own version of a template — a custom NDA, a house MSA — and returns it with its new version number.                                                                  |
| [`GET /v1/legal/templates`](https://docs.hanzo.ai/docs/openapi/legal/get-legal-templates)                                          | Returns the org's effective template catalog: every built-in template, with any the org has overridden replaced by its own latest version.                                           |

---

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