01
The shape of the thing
Sanctor is an authority engine: a private, permissioned, append-only hash chain compiled from your agreements. You integrate against one chain per relationship, such as a company, a trust, or a joint venture. Every chain stands alone. Nothing is shared between chains, there is no public network, and there is no token.
Three facts organize the whole API.
Everything is replay. The chain stores one ordered list of signed events, and nothing else. The book of rules in force, every past edition, every office and who held it when, the task pool, the cap table: all of it is computed from the list, never stored. This is why the read surface is small, and why you can verify everything yourself (see Reconstructing everything).
The model routes; the rules decide. A natural-language layer sits in front of the engine. It reads a question, finds the rule or clause that speaks to it, and wraps the answer. It never decides anything. After adoption, no model is involved in any decision. Every entry is sealed by the signatures the written rule names. You can also call the engine with rule ids directly and skip the model. The record comes out the same either way.
Only people, and keys they control, start anything. There is no admin, no owner, and no operator path. The compiler, the matrix, and the pool sit in the middle of arrows, never at their start. Every change begins with a key signing something, and every key's power traces to an adopted text, or to the founding entry itself.
02
The surface at a glance
One birth call, five verbs. Everything a client (a UI, a script, an agent) can ever do is in this table. Everything else in the product is one of these calls wearing clothes.
genesisCall zero. Births a chain: founders, threshold, clock, ground rulesThe GEN entry, the only self-authorizing entryproposeA document or drafted rule comes in: hashed, words extracted, compiled, queued at its doorA pool item (off the chain until it exits)signA key answers a pool item: approve, refuse, or withdrawThe item's exit entry, once settled (C/R/L/W/X)checkThe ask. What would happen, read from the book as it standsNothing; a pure readingdoThe act, sealed. Flavors: act, attest, bind, unbind, departOne entry, authorized on its facereadEntries, the book as of any date, trace, chain of title, the explorerNothing; pure replayTwo doors, one intake. check and sign form the authority door, answered by the signers the rule names. attest is the truth door, answered by those the fact concerns. propose is the intake: documents on their way to adoption. Nothing enters the chain any other way.
03
Keys and identity
A key is an identity on the chain: a person, an office holder, or an agent. There are no accounts, no usernames, and no admin who creates users. A key matters only when the chain says it does.
- Controllers (CTL) are born in the genesis entry. They are the only identities not created by an adopted text, because something has to adopt the first text. CTL seats change only by an adopted succession rule, never by bind or unbind.
- Office holders exist because an adopted rule names an office and a bind entry fills it. The bind needs two things: the appointment, at the required threshold, and the key's own acceptance signature. A key is never bound without signing its own binding.
- Agents (AGT), such as capability services, AI agents, or your own automation, are keys like any other, bound to a defined role. The chain records an agent's binding the same way it records a person's.
Signing is the whole of authentication. Every call that writes carries the caller's key, and the entry face records it forever. A key the book gives no power to can still attest facts that concern it, and can propose through a door that accepts from it. It can never confirm anything the rules do not let it confirm.
Who a key belongs to is your business, not the chain's. The chain stores keys; you keep your own labels. Keys in the examples below: k:4f1e, k:8c02, and k:d91a are founders, k:77aa is a counterparty, and k:a9e1 is an agent.
04
genesis: call zero
Genesis births a chain, and it is deliberately small. It seals only what cannot be adopted: who gets to adopt, and the rules that make adopting mean something. No rules, no roles, no people beyond the founders. The book is empty at birth.
Response, the GEN entry, sealed:
What the one call fixes for the chain's whole life:
- The control fact: the founding keys and the threshold. This is the CTL office. The GEN entry is the only entry not authorized by the book. The founders' signatures authorize it, and everything after answers to it.
- G1 to G5, the constitutive rules: the ground layer no adoption can amend away. Entries are append-only and hash-chained (G1). The book changes only by adoption through a door (G2). Pool items carry deadlines and lapse (G3). Measures describe and never decide (G4). Facts are attested by those they concern (G5).
- The clock:
deadline_days, inherited by every pool item ever opened.
A workspace is a chain, so genesis is also how you multiply. A new entity, a new trust, or a new venture is one more call. Each chain stands alone.
05
propose: documents and rules in
Propose is the one intake. A whole founding text, a single-rule amendment, or a resolution drafted from a dropped document all take the same path.
- The document is hashed and its words extracted. The hash and the words ride the chain. The file is handed back and never kept. Sanctor stores words and hashes, not files.
- The compiler turns it into rule drafts and checks them at the clarity gate. Nothing ambiguous can be proposed. The compiler returns what it could not read, and why.
- The drafts are assigned to their door: the rule whose consent the change needs, or the founding door if none exists yet.
- The item waits in the pool, with a deadline.
A founding text, right after genesis:
Response:
A later single-rule change uses the same call with a drafted rule instead of a document. It lands at whatever door the book assigns. One rule, one door, resolved from the adopted texts, never chosen by the caller.
Causes. Every proposal carries why it exists, as one code:
T:an instrument, by its hashL:a law. A law is never mandatory here; it only creates a proposal the parties can accept, change, or rejectA:a confirmed act being codifiedR:a refused act prompting reformF:a confirmed factPthe parties' own choice
Cause is not source. Law and facts can cause a rule; only adoption makes it binding.
Guards worth knowing: constitutive rules cannot be claimed by any door, no door may claim a rule that does not exist yet, and a waiting item goes stale if an adoption moves its rule's door.
06
sign: answering the pool
A pool item waits for the signatures its door names. Nothing else can move it. Each signer answers once:
Answers are + (approve), - (refuse), or withdraw (the bringer pulls their own item). The item sits off the chain while it waits; the chain never carries half-decided things. It leaves the pool exactly once, through one of five exits, each written as one entry.
The deadline comes from genesis (deadline_days) and starts at the item's birth. Lapse is not punishment; it is how the pool stays clean. Silence is an answer, written as L, and the proposal can always be brought again fresh.
Discussion happens on the item while it waits, and it is kept with the exit entry. Readable later from the record, never editable.
Versions and matters
A matter is a tag on pool items and entries. It describes and never decides. Every propose into a matter creates a new version. Versions never replace each other. They sit side by side as candidates, and each has its own id.
A version is private to its author until the first signature, which commits it to the pool. Each signer holds one live signature per matter. A signer may move it to another version or withdraw it until a version seals.
The first version to reach its threshold seals. Its siblings exit as S. A matter is refused only when no version can still reach the threshold. A matter has one clock, set when it opens, and every version in it lapses together.
kind is decision or fact. A fact is answered by those it concerns, all of them, with confirm or dispute. The consult at send time proposes the kind and the caller may override it before sending.
Documents
intake hashes a file, extracts its words into the matter's stream, and returns the hash. The bytes are not kept. verify takes a file and answers whether its hash is on the chain, and where.
07
check: the ask
Check is a pure reading: what would happen if this act were done now, answered from the book as it stands. Nothing is recorded, signed, or reserved. Call it as often as you like.
With natural language in front (the routed form; this is where the model lives):
Or with the model skipped entirely (the bare form; the result is identical):
Response, the reading:
Three answers are possible:
- Allowed alone. The rule lets this key act by itself;
dowill seal in one step. - Yes, with signatures.
doopens a pool item at the rule's signers. - The book is silent. No rule speaks. See the gap path under
do.
The trace field is the routing made visible: which rule matched, and why. It is returned as explanation and never written. The reading is honest only for the edition it names. do reads again at the head, so a book that changed in between changes the answer. That is the X exit.
08
do: the act
Do commits what check read. It reads the book again at the head, at the moment of sealing. Authority is checked once, on the entry's face, and never re-derived afterward. If the rule lets the key act alone, the entry seals in one step. If the rule names signers, do opens a pool item, and the entry seals when they confirm.
The flavors share one verb; only the answerers change.
- **
act**: conduct under a rule, as above. The authority door: the rule's signers. - **
attest**: a fact declared, such as "we signed the vendor agreement on Friday." The truth door: answered by those the fact concerns (G5), not by whoever the rules favor. Confirm or dispute, nothing in between. A fact is never authority. Admission is not cure; conduct outside the rules stays recorded as what it was. - **
bind/unbind**: a key takes or leaves an office. Bind needs the appointment at the required threshold, plus the key's own acceptance signature. Unbind is resignation (the key alone) or removal (the threshold). CTL is never bound or unbound. - **
depart**: conduct that departed from the book, recorded honestly: breach, discharge, or awaiting ratification. The record keeps what happened, not what should have happened.
The gap path. When check answers "the book is silent," the fact can still be recorded; the chain never refuses truth. The engine then drafts a proposal from the gap: the unmatched entry becomes a drafted rule, routed to its door like any other proposal. Codify what you confirmed (A:), reform what you refused (R:). The book grows at exactly the places life outran it.
09
read: everything back
Read is pure replay, grouped however the question needs. The useful forms:
One entry, resolved:
Every reference resolves at the moment asked about, not the moment of reading. The rule id resolves to the clause as it stood at that edition. The keys resolve to whoever held them that day. The instrument's words are on the chain under its hash. Supply the original file to verify and it is hashed again and matched. A changed file returns a mismatch, not a document.
Three separations live on every face, and none borrows from the others:
- Integrity: each entry hashes the one before it, so the list cannot be rewritten.
- Authority: the signatures on the face, checked once at seal, never re-derived.
- Chain of title: each rule's words trace version by version to the instrument that brought them.
10
Reconstructing everything
You never have to believe the server about state. You only trust the list, and the list is hash-chained. Given the entries, everything else is arithmetic:
An independent replayer is an afternoon's work:
H() is truncated SHA-256 over canonical JSON. apply is specified move by move. An adoption recompiles the book and must land on the same edition hash. Bind and unbind move seats. Exits close pool items. If your replayer and ours disagree on any derived value, one of us has a bug, and the entries will say which. There is no state to argue about, only the list.
What this buys in practice:
- Audit: an auditor runs the replayer, not an interview. Every register (minute book, resolutions, cap table) is reproducible from the list.
- Exit: the entries export whole, words and hashes included. Nothing about your governance is locked in our storage format.
- Dispute: "as of 1 June" is not a backup lookup. It is the same replay, stopped early. Every past state is first class.
- Integrations: your systems can act on our readings and spot-check them against their own replay.
11
Roles, capabilities, and agents
Roles need no sixth call. There is no create-role endpoint. An office exists because an adopted rule names it, as actor or approver. A bind entry fills it: the appointment plus the key's own acceptance. A defined but vacant office is a real, visible state. When a text creates an office, someone must be asked to fill it, or it sits empty. To rename or dissolve an office, amend the texts that name it. The org chart is a shadow of the agreements. Roles arrive inside propose (a text naming an office) and do (a bind filling it), and come back out inside read.
Capabilities are clients with keys. The filings agent, document reading, reminders, and the routing model itself: none has a private path into the engine, a special entry type, or a footnote in replay. Each holds a key, bound to a defined role, acting through the same five verbs as a person. This means a replayer never needs to know capabilities exist. You can ignore ours and build your own on the same calls. Turning one off breaks nothing; its key goes quiet, or is unbound with one more entry. Billing for capabilities is metered on the account and never written to the chain.
Agents are governed by adoption, not configuration. An agent acts by a key, so the book governs it exactly as it governs a person. A rule can cap what the filings agent may do, and its every act answers to that rule at seal. You do not configure your AI's permissions in a settings panel. You adopt them, with signatures, on the record.
Two lines from the demo chain: an agent is bound like anyone, and its work lands as ordinary entries.
12
Usage and metering
Every call returns what it cost, as a usage object on the response:
The rules are simple:
- One unit, one meter. Everything is billed in tokens: model work at its token count, and deterministic work (compiles, seals, replays, reads) normalized to token equivalents. A heavy replay costs more than a light read, and both show up the same way on the same bill. The bill is tokens plus the monthly subscription, nothing else.
- Input and output, on every response. Input tokens cover what the call carried in; output tokens cover what came back. Streaming responses report input tokens when the request is read and output tokens when the response finishes.
- Usage never touches the chain. It is metered on the account, returned on the response, and aggregated at
GET /account/usage. A billing number has no place on a sealed entry face.
Capabilities meter the same way: whatever a capability's key does shows up as that account's usage, so turning one on means faster token burn and nothing else changes.
13
Errors, guards, and notation
Every refused call returns Invalid with a reason in plain words. Nothing is partially applied; a refused call changes nothing. The guards you will actually meet:
L is refused, so propose afreshX, no sealNotation reference, what you will see on entry faces and in the explorer:
- Outcomes:
Cconfirmed,Rrefused,Llapsed,Wwithdrawn,Ssuperseded,Xfailed at seal,Ffact,Ddeparture,Aadoption,Ggenesis - Causes:
T:instrument,L:law,A:confirmed act,R:refused act,F:confirmed fact,Pparties' choice. One code, one meaning - Rules:
R-0002@2means rule 2, version 2. Adoptions writeR-0002@1 → R-0002@2 · hash. Refused changes writeR@v → — · hash - Signatures:
k:4f1e·CTL ▸ k:8c02·CTL+ k:d91a·CTL+, with the opener before▸and the answers after. Offices show as·CTL,·OWN,·AGT. A bare key is a personal attester - Hashes: truncated SHA-256 (12 hex) over canonical JSON. Entries, instruments, and editions all use the same
H()
One discipline ties all of this together: codes, hashes, and keys only. One number per row, nothing derived on a face. Anything computable is computed at read time by replay, so the sealed record never carries a number that could disagree with its own arithmetic.