Framework
Package framework is document types you define: describe a record once, then create, list, submit and cancel documents against it.
Package framework is document types you define: describe a record once, then create, list, submit and cancel documents against it.
| Base URL | https://api.hanzo.ai |
| Operations | 19 |
| Auth | Authorization: Bearer $HANZO_API_KEY |
framework
POST /v1/framework/{doctype}/{name}/cancel
Moves a submitted document to cancelled (docstatus 1 → 2) after its on_cancel hooks agree. Cancelling is terminal — a cancelled document cannot be re-submitted — but it CAN then be deleted.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | DocType is the document's DocType, from the path. |
name | path | string | yes | Name is the document's name — its key within the DocType — from the path. |
POST /v1/framework/{doctype}/{name}/submit
Moves a draft to submitted (docstatus 0 → 1) after its on_submit hooks agree. A submitted document is IMMUTABLE: further writes and deletes are refused until it is cancelled. Only a submittable DocType has this lifecycle; any other docstatus is an illegal transition.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | DocType is the document's DocType, from the path. |
name | path | string | yes | Name is the document's name — its key within the DocType — from the path. |
GET /v1/framework/{doctype}/{name}
Returns one document by name, with Password fields redacted.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | DocType is the document's DocType, from the path. |
name | path | string | yes | Name is the document's name — its key within the DocType — from the path. |
PUT /v1/framework/{doctype}/{name}
Replace a draft document's field data wholesale.
PUT semantics: the stored field data BECOMES the body, so a field the body omits is not left at its previous value. The body is the document's own field data — the same metadata-defined open object the create takes, and the same reason this operation publishes no request schema.
Only a DRAFT can be edited. A document that has been submitted or cancelled is immutable and the write is refused as a conflict, so the submit lifecycle cannot be bypassed by a plain update — cancel it first, and note that a cancelled document can be deleted but never re-submitted or re-edited. The engine validates the new data against the DocType, runs before_save (which may reject), writes, then runs the after hooks, and answers 200 with the stored document plus its managed envelope, Password fields redacted.
The document name in the path is percent-decoded before it is matched, so a name containing a space is addressed as it is stored. An unknown DocType or document is not found, and the same answer covers a document that exists in another tenant: the org comes from the validated principal and is part of the store key, so a caller cannot learn that another org's document exists. Write rights on the DocType are required, decided by the engine's permission calculus.
For a Single DocType the path name is ignored — there is one instance per org and this writes it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | |
name | path | string | yes |
DELETE /v1/framework/{doctype}/{name}
Removes one document, after its on_trash hooks agree. A SUBMITTED document cannot be deleted — cancel it first. Answers 204.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | DocType is the document's DocType, from the path. |
name | path | string | yes | Name is the document's name — its key within the DocType — from the path. |
GET /v1/framework/{doctype}
Returns the caller org's documents of one DocType, filtered, ordered and projected by the query. The DocType is resolved FIRST — through the same permission gate the list itself uses — because the query is validated against its schema: a filter, sort or field name the DocType does not declare is refused rather than reaching the store.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes | DocType is the DocType to list, from the path. |
filters | query | string | — | Filters is a JSON object of equality matches, e.g. {"priority":"High"}. |
fields | query | string | — | Fields projects the response to a subset — a JSON array ["a","b"] or a comma list "a,b". |
order_by | query | string | — | OrderBy is "<field> [asc|desc]". |
limit | query | string | — | Limit caps the rows returned. |
POST /v1/framework/{doctype}
Create one document of a DocType, from that DocType's own fields.
The body is the DOCUMENT'S field data: a flat JSON object whose properties are the fieldnames the DocType declares, not a fixed envelope. That is why this operation publishes no request schema — the shape is metadata the DocType defines at run time, and no Go struct both accepts it verbatim and describes it, so nothing is asserted rather than something false.
The engine validates and coerces every field against the DocType, runs the before_insert and before_save hooks (either may reject the write), stores the document, then runs the after hooks. It answers 201 with the stored document: the field data plus the managed envelope — name, doctype, docstatus, createdAt, updatedAt. A Password field comes back as a fixed redaction marker and is dropped when empty; its stored value is never returned by this or any other read on this surface.
name in the body is the REQUESTED DOCUMENT NAME, not a data field. A DocType with an autoname rule names the document itself and ignores it; a prompt-named DocType takes it. This collision is also why the two path segments cannot be folded into the body, and so why the route stays untyped.
Scoped to the org of the validated principal, and the engine's own permission calculus decides the rest: the caller needs create rights on this DocType through a role it holds, or a platform admin bit. A caller with no validated principal reaches the engine as the zero Caller and is refused before any store is opened — a forged org header alone buys nothing.
A DocType declared Single has exactly ONE document per org, so this writes that one instance instead of adding a row. The body is size-bounded by the engine, the same bound on every host.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
doctype | path | string | yes |
GET /v1/framework/doctypes/{name}
Returns one DocType definition — its fields, naming rule, permissions and lifecycle flags. Scoped to the caller's org, so another tenant's DocType of the same name is simply not found.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | yes | Name is the DocType's name, from the path. |
PUT /v1/framework/doctypes/{name}
Replaces a DocType definition wholesale (PUT semantics): the stored definition becomes the body. The name in the URL is authoritative over the body's, and documents already stored under the DocType are left intact. Manager-only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | yes |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
autoname | string | — | |
createdAt | integer | — | |
fields | DocField[] | — | |
isSingle | boolean | — | |
isSubmittable | boolean | — | |
module | string | — | |
name | string | — | |
permissions | DocPerm[] | — | |
titleField | string | — | |
updatedAt | integer | — |
DELETE /v1/framework/doctypes/{name}
Removes a DocType and every document stored under it. The definition and its data go together — a document with no schema can be neither validated nor read back — so there is no undo. Manager-only. Answers 204.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | yes | Name is the DocType's name, from the path. |
GET /v1/framework/doctypes
Returns every DocType defined in the caller's org. Another tenant's definitions are never included: the org is part of the store key.
POST /v1/framework/doctypes
Defines a DocType in the caller's org: the metadata that gives a document surface its fields, its naming rule, whether it has a submit/cancel lifecycle, and which role may do what to it. Manager-only — on a fresh org the first caller to administer it is seeded as its System Manager, after which only a System Manager (or a platform admin) may define. Answers 201.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
autoname | string | — | |
createdAt | integer | — | |
fields | DocField[] | — | |
isSingle | boolean | — | |
isSubmittable | boolean | — | |
module | string | — | |
name | string | — | |
permissions | DocPerm[] | — | |
titleField | string | — | |
updatedAt | integer | — |
POST /v1/framework/modules/{module}/install
Creates an app lane's DocTypes in the caller's org. Idempotent and create-if-absent: a DocType the org already has is reported as existing and never replaced, so re-installing cannot clobber a definition the org has since edited. Manager-only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
module | path | string | yes | Module is the lane's registered name ("cms", "erp"), from the path. |
GET /v1/framework/modules/{module}
Returns one app lane's install state for the caller's org: the DocTypes the lane declares, and which of them already exist in the org. That is the honest "set up" versus "installed" answer a console renders.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
module | path | string | yes | Module is the lane's registered name ("cms", "erp"), from the path. |
GET /v1/framework/modules
Returns every app lane compiled into this deployment and the DocTypes each one installs. It describes the BINARY, not the org: what a given org has actually installed is the per-module state below.
DELETE /v1/framework/roles/{user}/{role}
Removes one (user, role) grant in the caller's org. Manager-only. Answers 204; a grant that does not exist is not found.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
user | path | string | yes | User is the assignee whose grant is being revoked, from the path. |
role | path | string | yes | Role is the role to revoke, from the path. |
GET /v1/framework/roles
Returns every (user, role) assignment in the caller's org. Roles are what DocType permissions are written against, so this is the grant table the permission calculus resolves a member's rights from.
POST /v1/framework/roles
Grants one user one role in the caller's org — how a member gains rights on a DocType, since permissions name roles and never users. Manager-only. Answers 201.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
role | string | — | |
user | string | — |
GET /v1/framework/summary
Reports how much of the DocType surface the caller's org uses: how many DocTypes it has defined, and how many documents exist across them.
How is this guide?