Start
The AI contract
Munim's AI never types a number and never changes the books. Any frontend that shows AI output keeps those two promises by following this page.
1. Numbers arrive as references
AI prose carries no digits of its own. Every number, date or quotation is a reference token that the server already resolved against the business's own records:
⟨snap:<snapshot-id>·<row>·<column>⟩— one cell of a snapshot: a fixed, hashed query result minted by the core server.⟨cite:<kind>:<id>⟩, kind one ofrow,doc,msg,claim,snapshot— a cited record or a span of a document (·start-end).
The delimiters are U+27E8 ⟨, U+27E9 ⟩ and the middle dot U+00B7 ·. Each segment's refs array lists the bare ids it uses (snap:<id>, row:core.table:<id>).
{
"answer_id": "0192…",
"segments": [
{
"text": "Paneer cost rose to ⟨snap:0192…·4·unit_cost⟩ last week.",
"refs": ["snap:0192…"]
}
],
"abstained": false,
"reason_code": null
}
// resolved_refs (beside the envelope in the response):
[{ "ref": "⟨snap:0192…·4·unit_cost⟩", "value": 41000 }]2. Render references, not text
for each segment:
split segment.text on ref tokens ⟨…⟩
plain text → render as text (never as HTML)
ref token → look it up in resolved_refs by the exact token
found → format the value (money in minor units, the
business's locale) inside a citation chip that
opens the snapshot rows
not found → show the "Cannot verify" block instead
if envelope.abstained:
show "Cannot verify" with your copy for envelope.reason_codeShow the value inside a citation chip that opens the rows behind it (GET /v1/snapshots/{id}). Model text is always rendered as plain text — never through a raw-HTML path.
3. "Cannot verify" is an answer
When the server cannot trace a claim — a missing file, a reference that does not resolve, a number written outside a reference — the envelope comes back with abstained: true and a reason_code. Show a calm "Cannot verify" block with your own copy for that code. It is not an error state and never shows the model's own words.
The reason codes are listed on the Errors page.
4. Changes are drafts until a person approves
- Anything the AI proposes — a price, a purchase order, a roster, a listing — is a draft in the inbox, never applied by itself.
- Each proposed number is a reference shown beside its value. A person may edit a value; the edit is labelled as theirs.
- A named person with the authority approves (
POST /v1/drafts/{id}:approve) or rejects with a reason. If the numbers behind the draft changed since it was written, it comes backstaleand nothing runs. - Your UI must never offer an "auto-apply" state.
5. When AI is unavailable
Hide the AI surface or show a plain template. AI features degrade to hidden — never to an error screen.
Schemas
Rendered from the OpenAPI file.
- segmentsarray of objectrequired
- textstringrequiredmin length 1max length 2000
- abstainedbooleanrequired
- follow_upenum (1) | nulloptional
dig_deeper
- segmentsarray of objectrequired
- textstringrequiredmin length 1max length 2000
- impact_refstring | nullrequiredpattern ^⟨snap:[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}·(?:0|[1-9][0-9]*)·[a-z_][a-z0-9_]*⟩$
- abstainedbooleanrequired
- template_idstringrequiredpattern ^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$
- paramsmap of one of 4 | nullrequired
- outlet_scopeone of 2required
- columnsarray of objectrequired
- namestringrequiredpattern ^[a-z_][a-z0-9_]*$
- typeenum (7)required
integernumerictextdatetimestamptzbooleanuuid - numeric_sourceone of 2 | nulloptional
- rowsarray of map of one of 3 | nullrequiredmax items 500
- row_countintegerrequired≥ 0≤ 500
- sha256stringrequiredpattern ^[0-9a-f]{64}$
- turnobjectrequired
- turn_nointegerrequired≥ 1≤ 9007199254740991
- addressed_toenum (8) | nullrequired
cataloguekitcheninventory_purchasingfinancepeoplecustomerscompliancemarket - taintedbooleanrequired
- answerobjectrequired
- resolved_refsarray of objectrequired
- valueone of 3 | nullrequired
- signatureobjectrequired
- keyenum (2)required
answer.signature.via_manageranswer.signature.manager - specialistone of 2required
- name_keystringrequiredmin length 1