Policies
Your own rules, layered after the law.
A policy is your company's own rule set — a policy, a playbook, an SOP: what the company allows, whose approval something needs, how often, and which cases a named person decides. Where your account has one of our law sets switched on for its country, the policy is layered after the law, and the law decides the consequences — how much of a gift is deductible, whether input VAT may be claimed. Your policy decides the rest: a lower limit, an approval above an amount, a named person for the cases a word like "appropriate" leaves open. A policy may add limits, conditions and approvals; it can never change a consequence the law decides, and where the law sets a minimum owed to someone, a policy may never pay less.
A check answers the law first and then each of your published policies for the same domain, in layers.policies. Its overall state is the first, in order of not_covered, undetermined_missing_facts, contested, determined, that any layer reached.
A policy with no law under it
Your policy runs whether or not we hold law for your country. Where we hold a law set for its domain and country, the policy sits on it; where we hold none — or your account has not switched ours on — it stands alone, and it is the whole answer: layers holds your policies and no law, the answer states no legal consequence, and not_checked says so, { "topic": "the law", … }. Check against it by naming it: "rule_set": "policy.<your account>.<name>". Law is per country: a gift your German office books is answered by German law where your account has it on, one your US office books by your policy alone, and a gift booked in one country never counts toward another's limit.
A policy that stands alone says what is allowed, what needs whose approval and what a named person decides — each citing its clause. It sets no consequence, reads nothing of the law's answer (law.…) and grants no basis: goodwill: with no law beside it, nothing can tell a legal consequence from your company's own figure. Publishing refuses each, as consequence_without_law, law_read_without_law and goodwill_without_law.
A policy for several countries, or for any, says where each check falls through jurisdiction: where your account has our law on for one of those countries, a check against the policy that names none is 422 invalid-request, since which law applies turns on it.
Writing a policy
A policy is laid out like any rule set version: ruleset.yaml, the rules under rules/, its worked examples under tests/, and the policy document it cites under sources/. Post the files, and it is stored as a draft:
curl https://api.gethimmel.com/v1/policies \
-H "Authorization: Bearer $HIMMEL_KEY" -H "Content-Type: application/json" \
-d '{ "files": { "ruleset.yaml": "...", "rules/020-gifts.yaml": "...", "tests/policy.tests.yaml": "...", "sources/policy-gifts.md": "..." } }'
A policy is named policy.<your account>.<name>. A draft can be edited with PUT /v1/policies/{id} until it is published; a published version never changes.
GET /v1/policies/{id} runs, now, everything publishing would: lint, the consequence check, each of the policy's own cases over the law (or on their own, for a policy that stands alone), ten cases and a worked example for every rule, and the law floor. checks.blocking lists what would stop it, and sits_on the law versions it is layered over — the law of its domain and countries your account has switched on, and empty for a policy that stands alone. drafted_from names the document it was last drafted from (null for one posted as files), filled_from the template that filled it and your values (null otherwise), and review_items what that drafting raised, with each flag of a rule that stands flagged.
Starting from a template
A policy can start as one of our templates filled with your own figures. GET /v1/templates lists them — one so far, online_shop_support: a support playbook for an online shop, saying what its support team, its people and an AI assistant that asks before it acts, may give a customer — refunds, retention discounts and goodwill credits. Each template lists its blanks, each with its measure (money, days, percent or count), the clauses that say it and the least and most it takes; the order its words put them in; its choices, each a part of the playbook you pick between its words, with its options; the settings its rules read; and its document with each blank and choice shown by its name, 2.4 A refund of up to [refund_without_approval] needs no approval.
online_shop_support has one choice, refund_above_assistant (clause 2.7): what becomes of a refund above what the AI assistant gives on its own. hand_to_a_person - the assistant hands it to the team lead, and Himmel tells the team lead; or team_lead_approval - the assistant asks the team lead's approval first, Himmel asks the team lead, and the assistant gives it once they approve; above the team lead's band, the head of support's approval, as for any refund.
Every figure is a blank and every choice yours, and Himmel proposes none: the limits are your company's. Fill each one, in your account's currency, pick each choice, and post it in place of files:
curl https://api.gethimmel.com/v1/policies \
-H "Authorization: Bearer $HIMMEL_KEY" -H "Content-Type: application/json" \
-d '{ "template": "online_shop_support", "values": {
"refund_without_approval": { "amount": 10000, "currency": "USD" },
"refund_with_team_lead": { "amount": 50000, "currency": "USD" },
"refund_by_assistant": { "amount": 4000, "currency": "USD" },
"refund_days": 14,
"discount_without_approval": 10, "discount_with_team_lead": 20,
"credit_at_most": { "amount": 2500, "currency": "USD" },
"credits_in_window": 3, "credit_window_days": 30,
"credits_a_year": { "amount": 10000, "currency": "USD" },
"refund_above_assistant": "team_lead_approval" } }'
The answer is your policy, as a draft: its document saying your figures — "2.7 The AI assistant gives refunds of up to $40 on its own." — dated today, each figure written into the rule that reads it, and its worked examples worked out around your figures: at a limit, above it, within it. Your rule owner confirms each rule with its examples on the confirmation page, as for any policy; the examples are set by that confirmation, and the policy publishes once every rule is confirmed. Who approves — the team lead and the head of support — and when your financial year starts are settings, which your owner names. filled_from on the version says what filled it: the template, its version and your values - and so does each version GET /v1/policies lists. It is posted as your policy's 1.0.0, or the next version of the one you have; while a draft of it waits, posting again is 409 with that draft's policy_id, and PUT /v1/policies/{id} with template and values fills the draft again — with a figure changed, say: the rules the change reaches wait for your owner again, and the rest keep their confirmations.
A filling is refused rather than mended, each figure by values.<name> in errors: one left out (required), in another currency than your account's (other_currency), not a whole number (not_a_whole_number), outside what the blank takes (below_minimum, above_maximum), a choice left out (required) or not one of its options (not_an_option), or out of the order the template's words put them in (out_of_order, with the clauses): for online_shop_support, the team lead's approval covers refunds above what needs none, what the AI assistant gives on its own needs nobody's approval, the discounts' team-lead step is above the free one, and one credit is within a year's. A template is written in English; a playbook your owner confirms in another language is uploaded as a document instead.
Starting from a document
A policy usually starts as a document: upload it with POST /v1/policies/documents — PDF, DOCX or Markdown — and list the names in it that must not be kept, one names field each. Those names, every name your account's documents hid before, every person in your account, every word that reads as a name — a given name followed by a capitalised word, such as "Casey Wagner" — and every email address, IBAN and phone number are replaced by placeholders such as [[NAME-1]] before anything is stored; the file itself is not kept. The answer is the masked text with one anchor per clause - a PDF's running header and footer, repeated on its pages, left out - and masked, each placeholder with its kind and why: listed, person, found or shape. Read it: if a name is still there — a first name on its own, or one written in a way no list knows — hide it where it stands with POST /v1/policies/documents/{id}/names — { "names": ["Sam"] } — and it is masked in the copy that is stored, numbered after the document's own placeholders, as long as nothing has been drafted from it. A word hidden because it reads as a name, and that is none — a branch called after a city, a product — is shown again with POST /v1/policies/documents/{id}/shown — { "placeholders": ["[[NAME-3]]"] } — and the list leaves it alone in that document from then on; GET /v1/policies/documents/{id} shows each such word (value) to a person signed in who is shown names, an admin or ops, and to no key. A name you listed, a person in your account and an address stay hidden. A document you do not want, never sent to drafting, is withdrawn with POST /v1/policies/documents/{id}/withdraw: it is removed, its text with it, and the audit log keeps only that it was withdrawn and by whom. Once a document has been sent to drafting it stays as it is, since what was drafted from it cites it: upload it again with the name listed, and draft that one.
A Word document is read as Word prints it: where its clauses are in one of Word's numbered lists — 1. a section, 1.1 its clauses — they carry those numbers and become clauses, as typed numbers do; a list numbered at one level only, 1., 2. under each heading, reads as the text it sits in. Its tables are read where they stand, a row to a line and the cells joined by |, so an approval matrix is part of the text.
domain is your name for the policy's set of books — customer_support, say — short, lower case, its parts joined by dots; where the policy is to sit on one of our law sets, it is that law set's domain.
Drafting rules from it is an optional step: POST /v1/policies/documents/{id}/draft asks a language model to draft the rules from the masked text, and only ever the masked text — masked again as the draft is asked for, against the people in your account as they are then, so that a colleague who joined after the upload is hidden too. A document is drafted over the law your account has switched on for its domain; with none, it is drafted as your own rules standing alone — covering wherever your company acts, dated by a fact of their own, and in the currency your account keeps its books in. It takes minutes and runs as a job. A call that fails costs that call, never the draft: each reply is kept as it comes back, so a retry starts from the first call not done; an error no retry mends — the model provider refusing the server's key, or the account it drafts with out of credit — stops the drafting at once; and a drafting that stops leaves the document failed, its latest entry in drafts saying why in words (reason), and can be drafted again at once, reading the replies already back while the document reads the same. First the playbook's terms are written - what every rule and example will name: its facts, its settings, its outcomes, the questions a person decides - and checked; then two drafts are made over them, side by side, each its own way, and compared by what they answer. Where both can run an example and decide it differently, that is a review item under the rule it concerns, a few to a rule, each draft's answer under its name and chosen naming the draft your version holds; an example one of them cannot run is counted, never raised. While it runs, GET /v1/policies/documents/{id} says where it is in progress: the step - queued, terms, drafts, examples, gaps, again (a rule your owner flagged, drafted again), or waiting to try again, with when and why - since when, and each call thinking, writing and how far, or back. Before the draft reaches you it is held to what publishing will ask once every rule is confirmed: where a rule has too few examples, those alone are asked for, and each comes into the draft only once it comes out as it says - one that does not is a review item beside its rule; what would still stand in the way is listed in the drafting's entry (once_confirmed). Each example is then run again with one fact altered at a time, and an altered example a rule could not answer at all is a review item under that rule; every gap a third pass finds is one too. What a model drafts is a draft: every worked example arrives marked proposed - Himmel writes the mark, whatever the model wrote - and your rule owner sets it against the document by confirming the rule it is an example for — publishing refuses a drafted policy until each rule is confirmed, and then writes its examples as confirmed by the owner. Nothing runs until the rules are confirmed. A deployment with no model configured answers 503 drafting-not-configured, and a policy can always be written as files instead.
A rule your owner flags with a comment, on a policy drafted from its document, is drafted again by itself, alone, from the document and what they said (Confirmations): its entry in the document's drafts says again, and what came of each rule - drafted, or not_taken or skipped with why - and the document stays drafted whatever comes of it. A policy changes through its document. To change a clause the company has changed, revise the playbook, upload it, and draft it: the drafter is given the version it revises, with the document that version was drafted from, and keeps every rule whose clause did not change as it was written. Where the policy has a draft, the new drafting replaces it in place — the same version — so a rule that reads as it did, beside the same clause, keeps its confirmation; otherwise it drafts the next version. A rule is confirmed with the clause it cites, so one whose clause changed waits for your owner again even where its words did not. One document of a policy is drafted at a time: while one is, drafting another answers 409, with the document_id it waits for.
Publishing
POST /v1/policies/{id}/publish publishes a draft, or refuses with 409 policy-blocked and every finding in blocking:
- a rule that sets a consequence the law decides, named — or, for a policy that stands alone, any consequence, a reading of the law's answer, or goodwill;
- one of the policy's own cases that does not come out as it says;
- a rule reached by fewer than ten cases;
- a rule no case names as its worked example (
rule_without_example) — your rule owner confirms each rule with the examples written for it, so give each one a case whoseruleis its id; - a law case where the policy would pay less than the law says is owed, naming the case and the law's rule;
- a drafted example whose rule your rule owner has not confirmed (
case_source_still_proposed, naming the rule to confirm), or one that names no rule, which your owner would never read (drafted_case_names_no_rule).
A version applies from the date you say: send effective_from — { "effective_from": "2026-09-01", "changelog": "Goodwill credits capped at $15." } — and an action of that date or later is checked against it, an earlier one against the version before. A version that replaces a published one must say it (422 invalid-request, required): its own date is its document's, and a revised document often still gives the first version's. It may not be dated before the version it replaces (before_the_version_it_replaces); the same date corrects that version from the start. A date in the past is allowed: the actions since then are checked again under the new version once its rules are confirmed, and every earlier answer stays on record. A first version left without a date applies from its own, its document's.
Once published, the version before it is superseded, your admins are told, and its rules run as soon as your rule owner confirms them on the policy's confirmation page. Until then, a check that reaches one answers not_covered with awaiting_confirmation, exactly as a rule of the law would — and the answers you were given before it was published stand as they are. Once its rules are confirmed, those it applies to are checked again with the policy in them, with one checks.rerun alert. Where your policy says nothing about the facts, its layer answers not_covered with policy_gap: your policy does not say.
Trying a version
POST /v1/policies/{id}/evaluate answers facts — or a booking already stored, by its transaction_id — twice: under the law alone, and with the version layered over it, side by side. For a policy that stands alone, law_only is null and with_policy is the policy's own answer. Nothing is stored, no recipient is created, and confirmations are not applied: it shows what the rules say.
Say who acts with actor, as a check's transaction.actor says it — { "facts": { … }, "actor": { "kind": "agent", "id": "agt_refunds" } } — to see what a rule that turns on who acts makes of them; left out, it is you, as a check would record you, and an agent's own key acts as its agent. A booking already stored brings who acted and when, so it takes no actor, and it is answered as its check answered it: one that falls outside the countries of the rule set its check named is not_covered on both sides, no_rule_set_for_jurisdiction, as its check was. Otherwise the law is the one its check was answered under, the law of the country it fell in, and a version for other countries than that one is not layered on it: with_policy is not_covered, no_rule_set_for_jurisdiction, saying where the version applies, beside the law's answer. A booking of another domain than the version's is 422 invalid-request (other_domain).
GET /v1/sandbox/policy-sample returns an invented policy, labelled so in its first line, as a document and as the files it drafts to — written to hold the hard cases, including a clause that tries to say what is deductible, which publishing refuses.
Endpoints
/v1/policiesScope rules:readThis account's policies and their versions
Each policy with every version: its status, and the rules still waiting for your rule owner.
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Responses
200 Successful response
policieslist of PolicyListItemrequired4 fields
rule_setstringrequiredtitlestringrequireddomainstringrequiredversionslist of PolicyVersionSummaryrequired10 fields
policy_idstringrequiredrule_setstringrequiredversionstringrequiredstatusstringrequiredeffective_fromstringrequiredrulesintegerrequiredpending_confirmationlist of stringrequiredflaggedlist of stringrequiredsuperseded_bystring or nullfilled_fromFilledFrom or nullThe template that filled this version and the figures it was filled with; null for one posted as files or drafted from a document.
3 fields
templatestringrequiredThe template's name, as
GET /v1/templateslists it.versionstringrequiredThe template's own version when it filled this one.
valuesobjectrequiredEach blank's figure, by its name: money as
{amount, currency}, the rest whole numbers.
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/templatesScope rules:readThe templates a policy can be filled from
Each of our templates: what it is for, its blanks - each with its measure, the clauses that say it and the least and most it takes - the order its words put them in, its choices - a part you pick between its words, each with its options - the settings its rules read, and its document with each blank and choice shown by its name. Every figure is a blank and every choice yours: a template proposes none. Fill one with POST /v1/policies, template and values in place of files.
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Responses
200 Successful response
templateslist of Templaterequired12 fields
templatestringrequiredIts name: what
POST /v1/policiestakes astemplate.versionstringrequiredtitlestringrequiredsummarystringrequiredlanguagestringrequiredThe language its document, rules and examples are written in.
policystringrequiredThe policy a filling is posted as:
policy.<your slug>.<policy>.domainstringrequiredblankslist of TemplateBlankrequiredEvery figure it needs, each yours to fill: it proposes none.
6 fields
namestringrequiredThe blank's name, as
valuesgives its figure.kind"money" | "days" | "percent" | "count"requiredIts measure: money, an integer
amountin your account's currency's minor units with thatcurrency; days, whole percent or a count of things, a whole number.clauseslist of stringrequiredThe clauses of the template's document that say it.
saysstringrequiredWhat the figure is, in words.
minimumintegerrequiredThe least it takes - for money, in minor units.
maximumintegerrequiredThe most it takes - for money, in minor units.
orderlist of TemplateOrderrequiredThe order its words put figures in: a filling out of it is refused, naming the clauses, never mended.
5 fields
lowerstringrequiredupperstringrequiredstrictbooleanrequiredWhether
uppermust be abovelower, not only at least it.clauseslist of stringrequiredsaysstringrequired
choiceslist of TemplateChoicerequiredEach part of the playbook you pick between its words - for
online_shop_support, what becomes of the AI assistant's refund above its own limit (clause 2.7) - each yours to pick: it proposes none.4 fields
namestringrequiredThe choice's name, as
valuesgives the option picked.clauseslist of stringrequiredThe clauses of the template's document it decides.
saysstringrequiredWhat it decides, in words.
optionslist of TemplateOptionrequiredWhat it may be: one of them, yours to pick.
2 fields
valuestringrequiredWhat
valuesgives the choice, picking this one.saysstringrequiredWhat it does, in words.
settingslist of TemplateSettingrequiredThe settings its rules read - people and a date, which your rule owner names.
3 fields
namestringrequiredtypestringrequiredsaysstringrequired
documentstringrequiredIts document, each blank and each choice shown by its name in brackets:
[refund_days].
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policiesScope policies:writePost a policy as a draft version: its files, or a template filled with your figures
A policy is a rule set of your own, laid out like any other: ruleset.yaml and the files under rules/, tests/ and sources/. It is stored as a draft however it lints, and checks says what would stop it being published. It sits on our law set for its domain and country where we hold one; where we hold none it stands alone, and says what is allowed, what needs whose approval and what a named person decides - no consequence, and nothing read from the law. Or from a template (GET /v1/templates): template and values in place of files, every blank your figure, in your account's currency, and every choice your option. Its document, rules and worked examples say your figures, and it is posted as a draft your rule owner confirms rule by rule - as a new policy's 1.0.0, or the next version of the one you have; a draft of it already there is 409 and is filled again with PUT. filled_from says what filled it. Idempotent on Idempotency-Key.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
Idempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
filesmap of string or nullEach file's path within the rule set, and its text - the same layout as any rule set version. Posted as a draft;
status: draftinruleset.yaml. Leave it out to fill a template instead.templatestring or nullOne of our templates, by its name (
GET /v1/templates): filled withvalues, it is your policy's document, rules and worked examples, posted as a draft for your rule owner to confirm. In place offiles.valuesobject or nullEvery blank of the template and your figure for it, by the blank's name: money as an integer
amountin minor units with your account'scurrency, days, percent and counts as whole numbers - and every choice and thevalueof the option you pick, by the choice's name. Each is required: the template proposes no figure and no choice.by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
policy_idstringrequiredrule_setstringrequiredversionstringrequiredstatusstringrequiredeffective_fromstringrequiredrulesintegerrequiredpending_confirmationlist of stringrequiredflaggedlist of stringrequiredfilled_fromFilledFrom or nullrequiredThe template that filled this version and the figures it was filled with; null for one posted as files or drafted from a document.
3 fields
templatestringrequiredThe template's name, as
GET /v1/templateslists it.versionstringrequiredThe template's own version when it filled this one.
valuesobjectrequiredEach blank's figure, by its name: money as
{amount, currency}, the rest whole numbers.
titlestringrequireddomainstringrequiredjurisdictionslist of stringrequiredsits_onlist of stringrequiredThe law versions it is layered over,
rule_set@version. Empty for a policy that stands alone: one for a domain and country we hold no law for, which states outcomes only.filesmap of stringrequiredchecksPublishChecksrequiredEverything publishing would run, run now.
6 fields
publishablebooleanrequiredblockinglist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
warningslist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
casesCaseCountsrequired2 fields
passedintegerrequiredfailedintegerrequired
coveragemap of integerrequiredHow many cases reach each rule.
floorFloorSummaryrequired2 fields
lawsintegerrequiredpayments_comparedintegerrequired
drafted_fromDraftedFrom or nullrequiredThe document this version was last drafted from; null for one posted as files.
5 fields
document_idstringrequiredfilenamestringrequiredtitlestringrequiredcreated_atstringrequiredWhen the document was uploaded.
drafted_atstringrequiredWhen the drafting that wrote this version began.
review_itemslist of ReviewItemrequiredWhat its latest drafting raised - examples the two drafts decide differently, holes the third pass found, cases that fail, examples a rule could not answer once altered - and each flag of a rule that stands flagged.
5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
superseded_bystring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/{policy_id}Scope rules:readOne version: its files, and what blocks publishing it
checks runs everything publishing would run, now: lint, the consequence check, the policy's own cases over the law (or on their own, for a policy that stands alone), ten cases and a worked example per rule, and the law floor.
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Parameters
policy_idpath · stringrequired
Responses
200 Successful response
policy_idstringrequiredrule_setstringrequiredversionstringrequiredstatusstringrequiredeffective_fromstringrequiredrulesintegerrequiredpending_confirmationlist of stringrequiredflaggedlist of stringrequiredfilled_fromFilledFrom or nullrequiredThe template that filled this version and the figures it was filled with; null for one posted as files or drafted from a document.
3 fields
templatestringrequiredThe template's name, as
GET /v1/templateslists it.versionstringrequiredThe template's own version when it filled this one.
valuesobjectrequiredEach blank's figure, by its name: money as
{amount, currency}, the rest whole numbers.
titlestringrequireddomainstringrequiredjurisdictionslist of stringrequiredsits_onlist of stringrequiredThe law versions it is layered over,
rule_set@version. Empty for a policy that stands alone: one for a domain and country we hold no law for, which states outcomes only.filesmap of stringrequiredchecksPublishChecksrequiredEverything publishing would run, run now.
6 fields
publishablebooleanrequiredblockinglist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
warningslist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
casesCaseCountsrequired2 fields
passedintegerrequiredfailedintegerrequired
coveragemap of integerrequiredHow many cases reach each rule.
floorFloorSummaryrequired2 fields
lawsintegerrequiredpayments_comparedintegerrequired
drafted_fromDraftedFrom or nullrequiredThe document this version was last drafted from; null for one posted as files.
5 fields
document_idstringrequiredfilenamestringrequiredtitlestringrequiredcreated_atstringrequiredWhen the document was uploaded.
drafted_atstringrequiredWhen the drafting that wrote this version began.
review_itemslist of ReviewItemrequiredWhat its latest drafting raised - examples the two drafts decide differently, holes the third pass found, cases that fail, examples a rule could not answer once altered - and each flag of a rule that stands flagged.
5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
superseded_bystring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/{policy_id}Scope policies:writeNew files for a draft, or the draft filled again from its template
A draft changes until it is published; a published version never does. Confirmations of rules the edit did not touch are kept. template and values in place of files fill the draft again from a template - a figure changed, say - under its own version: the rules the change reaches wait for your rule owner again, the rest keep their confirmations.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
policy_idpath · stringrequired
Request body · application/json
filesmap of string or nullEach file's path within the rule set, and its text - the same layout as any rule set version. Posted as a draft;
status: draftinruleset.yaml. Leave it out to fill a template instead.templatestring or nullOne of our templates, by its name (
GET /v1/templates): filled withvalues, it is your policy's document, rules and worked examples, posted as a draft for your rule owner to confirm. In place offiles.valuesobject or nullEvery blank of the template and your figure for it, by the blank's name: money as an integer
amountin minor units with your account'scurrency, days, percent and counts as whole numbers - and every choice and thevalueof the option you pick, by the choice's name. Each is required: the template proposes no figure and no choice.by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
policy_idstringrequiredrule_setstringrequiredversionstringrequiredstatusstringrequiredeffective_fromstringrequiredrulesintegerrequiredpending_confirmationlist of stringrequiredflaggedlist of stringrequiredfilled_fromFilledFrom or nullrequiredThe template that filled this version and the figures it was filled with; null for one posted as files or drafted from a document.
3 fields
templatestringrequiredThe template's name, as
GET /v1/templateslists it.versionstringrequiredThe template's own version when it filled this one.
valuesobjectrequiredEach blank's figure, by its name: money as
{amount, currency}, the rest whole numbers.
titlestringrequireddomainstringrequiredjurisdictionslist of stringrequiredsits_onlist of stringrequiredThe law versions it is layered over,
rule_set@version. Empty for a policy that stands alone: one for a domain and country we hold no law for, which states outcomes only.filesmap of stringrequiredchecksPublishChecksrequiredEverything publishing would run, run now.
6 fields
publishablebooleanrequiredblockinglist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
warningslist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
casesCaseCountsrequired2 fields
passedintegerrequiredfailedintegerrequired
coveragemap of integerrequiredHow many cases reach each rule.
floorFloorSummaryrequired2 fields
lawsintegerrequiredpayments_comparedintegerrequired
drafted_fromDraftedFrom or nullrequiredThe document this version was last drafted from; null for one posted as files.
5 fields
document_idstringrequiredfilenamestringrequiredtitlestringrequiredcreated_atstringrequiredWhen the document was uploaded.
drafted_atstringrequiredWhen the drafting that wrote this version began.
review_itemslist of ReviewItemrequiredWhat its latest drafting raised - examples the two drafts decide differently, holes the third pass found, cases that fail, examples a rule could not answer once altered - and each flag of a rule that stands flagged.
5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
superseded_bystring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/{policy_id}/publishScope policies:writePublish a draft, if nothing stands in the way
Refused with policy-blocked and every finding in blocking when the policy would set a consequence the law decides, when one of its own cases does not come out as it says, when a rule has fewer than ten cases or no worked example (a case naming it), when it would pay less than the law says is owed, or while a drafted example waits for your rule owner to confirm the rule it is an example for. Otherwise the version is published, its drafted examples written as confirmed by the owner, and the one before it superseded. Its rules run once your rule owner confirms them. It applies from effective_from, which a version replacing a published one must give (422), never before that one's date.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
policy_idpath · stringrequiredIdempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
changelogstringWhat changed, and why, in a sentence or two.
effective_fromstring or nullThe date the version applies from: an action of that date or later is checked against it. Required for a version that replaces a published one, and never before that one's date; a first version left without one applies from its own date, its document's. A date in the past is allowed: the actions since then are checked again under it once its rules are confirmed, and every earlier answer stays on record.
Responses
200 Successful response
policy_idstringrequiredrule_setstringrequiredversionstringrequiredstatus"published"requiredeffective_fromstringrequiredwarningslist of PublishFindingrequired11 fields
checkstringrequiredlint,consequence,coverage,casesorfloor.codestring or nullrulestring or nullcasestring or nullmessagestring or nullfailureslist of string or nulllawstring or nulllaw_rulestring or nullpolicy_rulestring or nullowedanypaidany
supersedesstring or nulldiffDiffSummary or null4 fields
changedintegerrequiredaddedintegerrequiredremovedintegerrequiredunchangedintegerrequired
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/{policy_id}/evaluateScope checkDry-run a version: the law, and the law with it
Send facts, or the id of a stored transaction, and see the law's answer beside the answer with this version layered over it - or, for a policy that stands alone, the policy's answer, with law_only null. A stored transaction is answered with the law its check was answered under, where it fell; a version for other countries than that one is not_covered there, and a transaction of another domain is refused. Nothing is stored, no recipient is created, and confirmations are not applied: it shows what the rules say. A retry is always safe, so it takes no Idempotency-Key.
Needs a key with the scope check. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Parameters
policy_idpath · stringrequired
Request body · application/json
factsobject or nullactorActorIn or nullWho acts, as a check's
transaction.actorsays it: left out, the caller, as a check would record it. A stored transaction says who acted itself, so not besidetransaction_id.3 fields
kind"user" | "agent" | "system"idstring or nullThe agent's own identifier - or, for a person (
kind: user), their Himmel id: from your account's own keys a person of your account (unknown_user,left_the_account).on_behalf_ofstring or nullThe person the agent acts for, as your own systems identify them: an opaque id, never a name or an email address. They need no account here.
transaction_idstring or null
Responses
200 Successful response
dry_runtruerequiredpolicy_idstringrequiredrule_setstringrequiredversionstringrequiredstatusstringrequiredconfirmationsstringrequiredlaw_onlyDeterminedAnswer | UndeterminedAnswer | NotCoveredAnswer | ContestedAnswer or nullrequiredThe law's answer alone; null for a policy that stands alone.
one of 4
One of 4, told apart by
state.effective_datestringrequiredThe date the rules were applied as of.
as_ofstringrequiredThe moment the history was read.
layersLayersrequired2 fields
lawLayerAnswer or nullThe law's answer. Left out where no law set is part of the answer - your policy's alone, for a country we hold no law for or one your account has not switched on.
12 fields
rule_setstringrequiredrule_versionstringrequiredstate"determined" | "undetermined_missing_facts" | "not_covered" | "contested"requiredoutcomestring or nullbasisstring or nulllaw,policyorgoodwill.consequenceslist of Consequence or nullnot_checkedlist of NotChecked or nullapproveranyWho a policy says must approve, where it names one.
handed_toanyWhom a policy hands the action to, where its rule names one: a person in your account, by Himmel id. Where an agent asked about the action, Himmel tells them (
check.handed_over).tenant_facts_usedlist of string or nullYour settings this answer read.
reference_versionsmap of integer | string or nullWhich version of each reference table it read, such as dated VAT rates.
waiting_onstring or nullA policy rule that reads the law's answer waits for the law to settle:
law.
policieslist of LayerAnswer or nullYour policies for this domain, in the order they ran.
12 fields
rule_setstringrequiredrule_versionstringrequiredstate"determined" | "undetermined_missing_facts" | "not_covered" | "contested"requiredoutcomestring or nullbasisstring or nulllaw,policyorgoodwill.consequenceslist of Consequence or nullnot_checkedlist of NotChecked or nullapproveranyWho a policy says must approve, where it names one.
handed_toanyWhom a policy hands the action to, where its rule names one: a person in your account, by Himmel id. Where an agent asked about the action, Himmel tells them (
check.handed_over).tenant_facts_usedlist of string or nullYour settings this answer read.
reference_versionsmap of integer | string or nullWhich version of each reference table it read, such as dated VAT rates.
waiting_onstring or nullA policy rule that reads the law's answer waits for the law to settle:
law.
engine_versionstringrequiredrecipientRecipientSummary or null4 fields
resolutionstringrequiredresolved,unresolved,probable_matchormissing.recipient_idstring or nullreview_itemstring or nullThe open probable match, where there is one.
fy_totalMoney or nullThis recipient's total for the fiscal year, where the answer's first rule set totals money per recipient per fiscal year: the recipient's other bookings of the year that it counts, as known when the answer was given - this one not included, and later ones too where it counts the whole year. Left out where no such total was read;
history_usednames every total an answer read.2 fields
amountintegerrequiredcurrencystringrequired
history_usedlist of HistoryInput or null5 fields
rule_setstringrequiredinputstringrequiredThe rule set's name for this total, such as
recipient_fy_gifts.countintegerrequiredtransactionslist of HistoryTransactionrequired2 fields
transaction_idstringrequiredeffective_datestring or null
totalMoney | integer | string or null
not_checkedlist of NotChecked or null2 fields
topicstringrequiredreasonstringrequired
citationslist of Citation or null4 fields
sourcestringrequiredThe source's key within the rule set, such as
estg.paragraphstring or nullclausestring or nulltext_refstring or nullThe passage in the rule set's own copy of the source,
sources/<file>#<anchor>.
confirmationslist of ConfirmationUsed or null3 fields
rulestringrequiredconfirmed_bystring or nullconfirmed_atstring or null
decisionslist of DecisionRead or nullEach question on this action a person decided, read as its answer: where the question's rule says what each answer leads to, a sign-off or an admin's override issues the action's answer again, and every answer to it after reads the decision while the rule asks the very same question. Left out where none was read.
8 fields
answerstringrequiredThe answer chosen, one of the question's candidates - or
approved, for an approval.questionstring or nullThe question's id. Null for an approval, which answers none.
rulestring or nullThe rule that raises the question, as it asks it. Null for an approval.
decided_bystring or nullWho decided: a person in your account, by id.
method"sign_off" | "override" | "approval" or nullA sign-off by the person the question names, an admin's override of it, or the approval of the person the action's answer named, asked by Himmel.
resolution_idstring or nullThe decision's record, on the answer it was made on.
leads_tostring or nullWhat the answer led to:
continue- on to the rules after the question, which gave the outcome - or the outcome it gives itself. Null for an approval, read from the first rule.approvalstring or nullThe fact the decision stood in for as its decider's approval - where the action recorded none, and the rule that gave the outcome read it - so one person who decides and approves is asked once. Null otherwise.
recheckslist of Recheck or nullThe earlier answers this booking changed, each issued again before this one was given. Left out when it changed none, and on a proposal, which changes nothing until it is reported as executed.
4 fields
new_check_idstring or nullsupersedesstring or nullbooking_datestring or nulloutcomestring or null
supersedes_check_idstring or nullThe earlier answer for the same transaction that this one replaces.
recheck_reasonstring or nullWhy it was issued again: a later transaction, an action taken back (
reversal) or corrected (correction), a link or split between recipients, a question raised about its recipient, the rules changing, a question on it decided (decision), or the action approved by the person its answer named (approval).tracelist of TraceStep or nullEvery rule reached, in order. Left out when the check asked
explain: false.6 fields
rulestringrequiredstagestringrequiredscope,outcomeorconsequence.matchedboolean or nullresolveinteger or nullWhich of the rule's branches applied.
missinglist of string or nullnotestring or null
state: "determined"A dry run's determined answer: stored nowhere, so it has no id.
state: "undetermined_missing_facts"A dry run's answer that needs facts it did not get.
missinglist of MissingFactrequired7 fields
factstringrequiredtypestring or nullcurrencystring or nullFor an amount, the currency it is wanted in: the rule set's. Send it there, or - for an amount in another currency - beside it, as what your own systems record it as in this one (
equivalents).descriptionstring or nullneeded_bystring or nullThe rule that needed it.
review_itemstring or nullFor
recipient_identity: the probable match to answer first.ofHistoryTransaction or nullWhere the fact is another action's: a booking a total counts and cannot read, by its id and its date. Send the fact by completing that booking (
transaction.completes), not in this check.2 fields
transaction_idstringrequiredeffective_datestring or null
state: "not_covered"A dry run's answer that no rule covers.
reason"awaiting_confirmation" | "rule_flagged" | "policy_gap" | "no_rule_matched" | "no_rule_set_for_jurisdiction" | "rule_set_broken"requireddetailstring or nullunconfirmed_ruleslist of string or null
state: "contested"A dry run's answer that turns on a word a person decides.
questionQuestionrequired5 fields
idstringrequiredcandidateslist of stringrequiredreasonstringrequiredWhy this one cannot be settled by the rule.
rulestringrequiredwordingstring or nullThe rule's wording, as your rule owner confirmed it.
signerSigner or null1 field
useranyrequiredThe person who signs off, as your settings name them.
with_policyDeterminedAnswer | UndeterminedAnswer | NotCoveredAnswer | ContestedAnswerrequiredone of 4
One of 4, told apart by
state.effective_datestringrequiredThe date the rules were applied as of.
as_ofstringrequiredThe moment the history was read.
layersLayersrequired2 fields
lawLayerAnswer or nullThe law's answer. Left out where no law set is part of the answer - your policy's alone, for a country we hold no law for or one your account has not switched on.
12 fields
rule_setstringrequiredrule_versionstringrequiredstate"determined" | "undetermined_missing_facts" | "not_covered" | "contested"requiredoutcomestring or nullbasisstring or nulllaw,policyorgoodwill.consequenceslist of Consequence or nullnot_checkedlist of NotChecked or nullapproveranyWho a policy says must approve, where it names one.
handed_toanyWhom a policy hands the action to, where its rule names one: a person in your account, by Himmel id. Where an agent asked about the action, Himmel tells them (
check.handed_over).tenant_facts_usedlist of string or nullYour settings this answer read.
reference_versionsmap of integer | string or nullWhich version of each reference table it read, such as dated VAT rates.
waiting_onstring or nullA policy rule that reads the law's answer waits for the law to settle:
law.
policieslist of LayerAnswer or nullYour policies for this domain, in the order they ran.
12 fields
rule_setstringrequiredrule_versionstringrequiredstate"determined" | "undetermined_missing_facts" | "not_covered" | "contested"requiredoutcomestring or nullbasisstring or nulllaw,policyorgoodwill.consequenceslist of Consequence or nullnot_checkedlist of NotChecked or nullapproveranyWho a policy says must approve, where it names one.
handed_toanyWhom a policy hands the action to, where its rule names one: a person in your account, by Himmel id. Where an agent asked about the action, Himmel tells them (
check.handed_over).tenant_facts_usedlist of string or nullYour settings this answer read.
reference_versionsmap of integer | string or nullWhich version of each reference table it read, such as dated VAT rates.
waiting_onstring or nullA policy rule that reads the law's answer waits for the law to settle:
law.
engine_versionstringrequiredrecipientRecipientSummary or null4 fields
resolutionstringrequiredresolved,unresolved,probable_matchormissing.recipient_idstring or nullreview_itemstring or nullThe open probable match, where there is one.
fy_totalMoney or nullThis recipient's total for the fiscal year, where the answer's first rule set totals money per recipient per fiscal year: the recipient's other bookings of the year that it counts, as known when the answer was given - this one not included, and later ones too where it counts the whole year. Left out where no such total was read;
history_usednames every total an answer read.2 fields
amountintegerrequiredcurrencystringrequired
history_usedlist of HistoryInput or null5 fields
rule_setstringrequiredinputstringrequiredThe rule set's name for this total, such as
recipient_fy_gifts.countintegerrequiredtransactionslist of HistoryTransactionrequired2 fields
transaction_idstringrequiredeffective_datestring or null
totalMoney | integer | string or null
not_checkedlist of NotChecked or null2 fields
topicstringrequiredreasonstringrequired
citationslist of Citation or null4 fields
sourcestringrequiredThe source's key within the rule set, such as
estg.paragraphstring or nullclausestring or nulltext_refstring or nullThe passage in the rule set's own copy of the source,
sources/<file>#<anchor>.
confirmationslist of ConfirmationUsed or null3 fields
rulestringrequiredconfirmed_bystring or nullconfirmed_atstring or null
decisionslist of DecisionRead or nullEach question on this action a person decided, read as its answer: where the question's rule says what each answer leads to, a sign-off or an admin's override issues the action's answer again, and every answer to it after reads the decision while the rule asks the very same question. Left out where none was read.
8 fields
answerstringrequiredThe answer chosen, one of the question's candidates - or
approved, for an approval.questionstring or nullThe question's id. Null for an approval, which answers none.
rulestring or nullThe rule that raises the question, as it asks it. Null for an approval.
decided_bystring or nullWho decided: a person in your account, by id.
method"sign_off" | "override" | "approval" or nullA sign-off by the person the question names, an admin's override of it, or the approval of the person the action's answer named, asked by Himmel.
resolution_idstring or nullThe decision's record, on the answer it was made on.
leads_tostring or nullWhat the answer led to:
continue- on to the rules after the question, which gave the outcome - or the outcome it gives itself. Null for an approval, read from the first rule.approvalstring or nullThe fact the decision stood in for as its decider's approval - where the action recorded none, and the rule that gave the outcome read it - so one person who decides and approves is asked once. Null otherwise.
recheckslist of Recheck or nullThe earlier answers this booking changed, each issued again before this one was given. Left out when it changed none, and on a proposal, which changes nothing until it is reported as executed.
4 fields
new_check_idstring or nullsupersedesstring or nullbooking_datestring or nulloutcomestring or null
supersedes_check_idstring or nullThe earlier answer for the same transaction that this one replaces.
recheck_reasonstring or nullWhy it was issued again: a later transaction, an action taken back (
reversal) or corrected (correction), a link or split between recipients, a question raised about its recipient, the rules changing, a question on it decided (decision), or the action approved by the person its answer named (approval).tracelist of TraceStep or nullEvery rule reached, in order. Left out when the check asked
explain: false.6 fields
rulestringrequiredstagestringrequiredscope,outcomeorconsequence.matchedboolean or nullresolveinteger or nullWhich of the rule's branches applied.
missinglist of string or nullnotestring or null
state: "determined"A dry run's determined answer: stored nowhere, so it has no id.
state: "undetermined_missing_facts"A dry run's answer that needs facts it did not get.
missinglist of MissingFactrequired7 fields
factstringrequiredtypestring or nullcurrencystring or nullFor an amount, the currency it is wanted in: the rule set's. Send it there, or - for an amount in another currency - beside it, as what your own systems record it as in this one (
equivalents).descriptionstring or nullneeded_bystring or nullThe rule that needed it.
review_itemstring or nullFor
recipient_identity: the probable match to answer first.ofHistoryTransaction or nullWhere the fact is another action's: a booking a total counts and cannot read, by its id and its date. Send the fact by completing that booking (
transaction.completes), not in this check.2 fields
transaction_idstringrequiredeffective_datestring or null
state: "not_covered"A dry run's answer that no rule covers.
reason"awaiting_confirmation" | "rule_flagged" | "policy_gap" | "no_rule_matched" | "no_rule_set_for_jurisdiction" | "rule_set_broken"requireddetailstring or nullunconfirmed_ruleslist of string or null
state: "contested"A dry run's answer that turns on a word a person decides.
questionQuestionrequired5 fields
idstringrequiredcandidateslist of stringrequiredreasonstringrequiredWhy this one cannot be settled by the rule.
rulestringrequiredwordingstring or nullThe rule's wording, as your rule owner confirmed it.
signerSigner or null1 field
useranyrequiredThe person who signs off, as your settings name them.
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documentsScope policies:writeUpload a policy document: stored masked, never drafted yet
PDF, DOCX or Markdown. List every name in it to hide, one names field each. Those names, every name your account's documents hid before, every person of your account, every word that reads as a name - a given name followed by a capitalised word - and every email address, IBAN and phone number are replaced by placeholders before anything is stored; the file itself is not kept. Read the masked text that comes back: a single first name, or a name written otherwise, is still yours to find, and a word hidden as a name that is none is shown again with …/shown. Nothing is drafted until you ask.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
Idempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · multipart/form-data
filestringrequiredpolicystringrequiredThe name it drafts to: policy.<your slug>.<policy>
domainstringrequiredYour name for its set of books -
customer_support, say, or a law set's domain where it is to sit on one: short, lower case, parts joined by dotstitlestringnameslist of string or nullEvery name in the document to hide, once per form field, as written.
by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
document_idstringrequiredrule_setstringrequireddomainstringrequiredtitlestringrequiredfilenamestringrequiredmedia_typestringrequiredsha256stringrequiredThe file's hash. The file itself is not kept.
statusstringrequireduploaded,drafting,draftedorfailed.textstringrequiredThe masked text, one anchor per clause.
clauseslist of stringrequiredmaskedlist of MaskedItemrequired4 fields
placeholderstringrequiredWhat stands in the text, such as
[[NAME-1]].kindstringrequiredname,email,ibanorphone.why"listed" | "person" | "found" | "shape"requiredWhy it was hidden:
listed- on this upload, or on an earlier document of your account;person- a person of your account, by the name Himmel keeps for them;found- it reads as a name, a given name followed by a capitalised word, and you show it again where it is none;shape- an email address, an IBAN or a phone number.valuestring or nullFor a word hidden because it reads as a name, the word, so that you can tell whether it is one: on
GET, to a person signed in who is shown names (an admin or ops). Null otherwise - every other value, and to a key, is never returned.
draftslist of objectrequiredOne entry per draft run: each call's prompt,
prompt_hash,model_ref, outcome and tokens (usage) - the terms (terms), each draft (attempts, each saying where it departs from the terms), the examples asked for (examples) and the hunt for gaps (adversarial) - the version it wrote (policy_id), how many examples the two drafts decide differently (disagreements) and how many one could not run (not_compared), the probe (probe), what publishing would still ask once every rule is confirmed (once_confirmed), the seconds each step took (took), and the ids of the review items it raised (review_items). A run that could not go on saysoutcome: stopped, why in words (reason), what stopped it (error) and the calls it made (calls): the document isfailed, and can be drafted again.review_itemslist of ReviewItemrequired5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
created_atstringrequiredupdated_atstringrequiredprogressDraftingProgress or nullWhere its drafting is, while one is under way (
drafting); null otherwise.9 fields
step"queued" | "terms" | "drafts" | "examples" | "gaps" | "again" | "waiting"requiredqueued- asked for, no worker has taken it up yet;terms- the playbook's terms, what every rule and example will name;drafts- the two drafts, side by side;examples- the examples a rule is short of;gaps- the hunt for gaps;again- each rule its owner flagged with a comment, drafted again alone;waiting- to try again (retry_at,why).sincestringrequiredWhen this step began.
job_idstring or nullattemptinteger or nullWhich attempt this is, of
of.ofinteger or nullstarted_atstring or nullWhen this attempt began.
callsmap of CallProgressEach call of the step, by its prompt -
terms,draft_a,draft_b, ... - or, for a rule drafted again, by the rule's id.retry_atstring or nullWaiting: when the next attempt begins.
whystring or nullWaiting: why the last attempt brought no reply.
nextstring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documentsScope rules:readThis account's uploaded policy documents
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Responses
200 Successful response
documentslist of PolicyDocumentListItemrequiredNewest first.
7 fields
document_idstringrequiredrule_setstringrequireddomainstringrequiredtitlestringrequiredfilenamestringrequiredstatusstringrequiredcreated_atstringrequired
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documents/{document_id}Scope rules:readOne document, masked, and its drafts
The masked text, its clauses, what was masked and why, and what drafting has made of it. No value masked is returned, but a word hidden because it reads as a name: to a person signed in who is shown names - an admin or ops - so that they can tell whether it is one.
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Parameters
document_idpath · stringrequired
Responses
200 Successful response
document_idstringrequiredrule_setstringrequireddomainstringrequiredtitlestringrequiredfilenamestringrequiredmedia_typestringrequiredsha256stringrequiredThe file's hash. The file itself is not kept.
statusstringrequireduploaded,drafting,draftedorfailed.textstringrequiredThe masked text, one anchor per clause.
clauseslist of stringrequiredmaskedlist of MaskedItemrequired4 fields
placeholderstringrequiredWhat stands in the text, such as
[[NAME-1]].kindstringrequiredname,email,ibanorphone.why"listed" | "person" | "found" | "shape"requiredWhy it was hidden:
listed- on this upload, or on an earlier document of your account;person- a person of your account, by the name Himmel keeps for them;found- it reads as a name, a given name followed by a capitalised word, and you show it again where it is none;shape- an email address, an IBAN or a phone number.valuestring or nullFor a word hidden because it reads as a name, the word, so that you can tell whether it is one: on
GET, to a person signed in who is shown names (an admin or ops). Null otherwise - every other value, and to a key, is never returned.
draftslist of objectrequiredOne entry per draft run: each call's prompt,
prompt_hash,model_ref, outcome and tokens (usage) - the terms (terms), each draft (attempts, each saying where it departs from the terms), the examples asked for (examples) and the hunt for gaps (adversarial) - the version it wrote (policy_id), how many examples the two drafts decide differently (disagreements) and how many one could not run (not_compared), the probe (probe), what publishing would still ask once every rule is confirmed (once_confirmed), the seconds each step took (took), and the ids of the review items it raised (review_items). A run that could not go on saysoutcome: stopped, why in words (reason), what stopped it (error) and the calls it made (calls): the document isfailed, and can be drafted again.review_itemslist of ReviewItemrequired5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
created_atstringrequiredupdated_atstringrequiredprogressDraftingProgress or nullWhere its drafting is, while one is under way (
drafting); null otherwise.9 fields
step"queued" | "terms" | "drafts" | "examples" | "gaps" | "again" | "waiting"requiredqueued- asked for, no worker has taken it up yet;terms- the playbook's terms, what every rule and example will name;drafts- the two drafts, side by side;examples- the examples a rule is short of;gaps- the hunt for gaps;again- each rule its owner flagged with a comment, drafted again alone;waiting- to try again (retry_at,why).sincestringrequiredWhen this step began.
job_idstring or nullattemptinteger or nullWhich attempt this is, of
of.ofinteger or nullstarted_atstring or nullWhen this attempt began.
callsmap of CallProgressEach call of the step, by its prompt -
terms,draft_a,draft_b, ... - or, for a rule drafted again, by the rule's id.retry_atstring or nullWaiting: when the next attempt begins.
whystring or nullWaiting: why the last attempt brought no reply.
nextstring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documents/{document_id}/namesScope policies:writeHide more names in a document not drafted yet
Each name is masked where it stands in the stored text, as the upload masks one: the name to the vault, a placeholder in its place, and the clauses read again. For a document not drafted - uploaded, or failed - so a name you find reading the masked text back is hidden before anything reaches a model; one drafted or being drafted is 409, since what was drafted from it cites its text as it was. Idempotent on Idempotency-Key.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
document_idpath · stringrequiredIdempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
nameslist of stringrequiredEach name to hide, as the document writes it; another way of writing it is another entry.
by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
document_idstringrequiredrule_setstringrequireddomainstringrequiredtitlestringrequiredfilenamestringrequiredmedia_typestringrequiredsha256stringrequiredThe file's hash. The file itself is not kept.
statusstringrequireduploaded,drafting,draftedorfailed.textstringrequiredThe masked text, one anchor per clause.
clauseslist of stringrequiredmaskedlist of MaskedItemrequired4 fields
placeholderstringrequiredWhat stands in the text, such as
[[NAME-1]].kindstringrequiredname,email,ibanorphone.why"listed" | "person" | "found" | "shape"requiredWhy it was hidden:
listed- on this upload, or on an earlier document of your account;person- a person of your account, by the name Himmel keeps for them;found- it reads as a name, a given name followed by a capitalised word, and you show it again where it is none;shape- an email address, an IBAN or a phone number.valuestring or nullFor a word hidden because it reads as a name, the word, so that you can tell whether it is one: on
GET, to a person signed in who is shown names (an admin or ops). Null otherwise - every other value, and to a key, is never returned.
draftslist of objectrequiredOne entry per draft run: each call's prompt,
prompt_hash,model_ref, outcome and tokens (usage) - the terms (terms), each draft (attempts, each saying where it departs from the terms), the examples asked for (examples) and the hunt for gaps (adversarial) - the version it wrote (policy_id), how many examples the two drafts decide differently (disagreements) and how many one could not run (not_compared), the probe (probe), what publishing would still ask once every rule is confirmed (once_confirmed), the seconds each step took (took), and the ids of the review items it raised (review_items). A run that could not go on saysoutcome: stopped, why in words (reason), what stopped it (error) and the calls it made (calls): the document isfailed, and can be drafted again.review_itemslist of ReviewItemrequired5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
created_atstringrequiredupdated_atstringrequiredprogressDraftingProgress or nullWhere its drafting is, while one is under way (
drafting); null otherwise.9 fields
step"queued" | "terms" | "drafts" | "examples" | "gaps" | "again" | "waiting"requiredqueued- asked for, no worker has taken it up yet;terms- the playbook's terms, what every rule and example will name;drafts- the two drafts, side by side;examples- the examples a rule is short of;gaps- the hunt for gaps;again- each rule its owner flagged with a comment, drafted again alone;waiting- to try again (retry_at,why).sincestringrequiredWhen this step began.
job_idstring or nullattemptinteger or nullWhich attempt this is, of
of.ofinteger or nullstarted_atstring or nullWhen this attempt began.
callsmap of CallProgressEach call of the step, by its prompt -
terms,draft_a,draft_b, ... - or, for a rule drafted again, by the rule's id.retry_atstring or nullWaiting: when the next attempt begins.
whystring or nullWaiting: why the last attempt brought no reply.
nextstring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documents/{document_id}/shownScope policies:writeShow again a word hidden as a name that is none
A word that reads as a name - a given name followed by a capitalised word - is hidden at upload without being listed (why: found), and GET shows it to an admin or ops. Where one is no name - a branch called after a city, a product - list its placeholder here: it is put back where it stands, as it was first written, the clauses are read again, and it is not hidden for reading as a name in this document again. A name you listed, a person of your account and an address or a number stay hidden (422 invalid-request, not_read_as_a_name). For a document not drafted, uploaded or failed; one drafting or drafted is 409, since what was drafted from it cites its text. Idempotent on Idempotency-Key.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
document_idpath · stringrequiredIdempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
placeholderslist of stringrequiredEach word's placeholder, as the text writes it:
[[NAME-3]]. Only a word hidden because it reads as a name (why: found) is shown again.by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
document_idstringrequiredrule_setstringrequireddomainstringrequiredtitlestringrequiredfilenamestringrequiredmedia_typestringrequiredsha256stringrequiredThe file's hash. The file itself is not kept.
statusstringrequireduploaded,drafting,draftedorfailed.textstringrequiredThe masked text, one anchor per clause.
clauseslist of stringrequiredmaskedlist of MaskedItemrequired4 fields
placeholderstringrequiredWhat stands in the text, such as
[[NAME-1]].kindstringrequiredname,email,ibanorphone.why"listed" | "person" | "found" | "shape"requiredWhy it was hidden:
listed- on this upload, or on an earlier document of your account;person- a person of your account, by the name Himmel keeps for them;found- it reads as a name, a given name followed by a capitalised word, and you show it again where it is none;shape- an email address, an IBAN or a phone number.valuestring or nullFor a word hidden because it reads as a name, the word, so that you can tell whether it is one: on
GET, to a person signed in who is shown names (an admin or ops). Null otherwise - every other value, and to a key, is never returned.
draftslist of objectrequiredOne entry per draft run: each call's prompt,
prompt_hash,model_ref, outcome and tokens (usage) - the terms (terms), each draft (attempts, each saying where it departs from the terms), the examples asked for (examples) and the hunt for gaps (adversarial) - the version it wrote (policy_id), how many examples the two drafts decide differently (disagreements) and how many one could not run (not_compared), the probe (probe), what publishing would still ask once every rule is confirmed (once_confirmed), the seconds each step took (took), and the ids of the review items it raised (review_items). A run that could not go on saysoutcome: stopped, why in words (reason), what stopped it (error) and the calls it made (calls): the document isfailed, and can be drafted again.review_itemslist of ReviewItemrequired5 fields
review_itemstringrequiredkindstringrequiredstatusstringrequiredpayloadobjectrequiredcreated_atstring or null
created_atstringrequiredupdated_atstringrequiredprogressDraftingProgress or nullWhere its drafting is, while one is under way (
drafting); null otherwise.9 fields
step"queued" | "terms" | "drafts" | "examples" | "gaps" | "again" | "waiting"requiredqueued- asked for, no worker has taken it up yet;terms- the playbook's terms, what every rule and example will name;drafts- the two drafts, side by side;examples- the examples a rule is short of;gaps- the hunt for gaps;again- each rule its owner flagged with a comment, drafted again alone;waiting- to try again (retry_at,why).sincestringrequiredWhen this step began.
job_idstring or nullattemptinteger or nullWhich attempt this is, of
of.ofinteger or nullstarted_atstring or nullWhen this attempt began.
callsmap of CallProgressEach call of the step, by its prompt -
terms,draft_a,draft_b, ... - or, for a rule drafted again, by the rule's id.retry_atstring or nullWaiting: when the next attempt begins.
whystring or nullWaiting: why the last attempt brought no reply.
nextstring or null
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documents/{document_id}/withdrawScope policies:writeWithdraw a document never sent to drafting
The document is removed, and its text with it; the audit log keeps that it was withdrawn and by whom, never what it said. One sent to drafting is 409: what was drafted from it cites it. Idempotent on Idempotency-Key.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
document_idpath · stringrequiredIdempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
200 Successful response
document_idstringrequiredstatus"withdrawn"required
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.
/v1/policies/documents/{document_id}/draftScope policies:writeDraft rules from a document whose masked text you have read
An optional step: drafting uses a language model on the masked text, and takes minutes, so it runs as a job - the document says drafted or failed when it is done. Before it is queued the stored text is masked again, where nothing drafted from it cites it yet: against your account's people as they are now, the names your other documents hid, and what reads as a name - so a colleague who joined after the upload is hidden too. Two drafts are made independently and compared by what they answer; where they differ, and every hole a third pass finds, becomes a review item. A document is drafted over the law your account has switched on for its domain, or, with none, as your own rules standing alone - covering wherever you act, and dated by a fact of their own. Nothing drafted runs until your rule owner confirms it, and confirming a rule sets the examples drafted for it. A policy changes through its document: drafting a revised one gives the drafter the version it revises, and replaces the policy's draft in place where it has one, so a rule that reads as it did beside the same clause keeps its confirmation. A call that fails costs that call: each reply is kept as it comes back, a retry starts from the first call not done, and an error no retry mends - a key refused, an account out of credit - stops the drafting at once. A drafting that stops says why in its entry of drafts, and the document can be drafted again, reading the replies already back while it reads the same. One document of a policy is drafted at a time (409). Answers 503 in a deployment with no model configured; a policy can always be posted as files instead.
Needs a key with the scope policies:write. It changes what your account has decided, which live and test share, so it is done from live: in an account with a live side, a test key gets 403 live-only.
Parameters
document_idpath · stringrequiredIdempotency-Keyheader · string or nullMakes a retry safe: the same key with the same request within 24 hours gets the first answer again, and nothing is done twice. The same key with a different request is
409 idempotency-conflict. Keys are per environment and per path.
Request body · application/json
by_userstring or nullWho did it, when your key acts for a person: their Himmel id, which the console's Developers page shows them, and Settings' People an admin. They must be in your account, with a role that could do this themselves, and the record keeps it as your key's claim. A key made for an agent names nobody but itself: leave it out. Signed in to the console, leave it out: it is you.
Responses
202 The draft is queued.
document_idstringrequiredstatus"drafting"requiredjob_idstringrequired
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 404Nothing with that id or name exists for this account.
- 409The request conflicts with what is stored: see
detail. - 413The request's body is larger than the operation takes, refused before any of it is read (
body-too-large): a policy's files at most 5 MB, any other body 1 MB - and an uploaded file at most 20 MB (file-too-large). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs. - 503An optional part of the service is not configured in this deployment, or a service it relies on did not answer:
typesays which.
/v1/sandbox/policy-sampleScope rules:readA synthetic company policy, as a document and as the rules it should draft to
"Beispiel GmbH", invented and labelled so in its first line, written to hold the hard cases: a limit with a named approver, a per-recipient cap stricter than the law's, a vague word left to a named signer, a kind of entertainment it never mentions, and a clause that tries to say what is deductible, which publishing refuses. files can be posted to POST /v1/policies as they are.
Needs a key with the scope rules:read. What it reads is your whole account's, so a key made for an agent, which reads its own agent's alone, gets 403 insufficient-scope.
Responses
200 Successful response
synthetictruerequiredrule_setstringrequireddocumentstringrequiredThe sample policy as a document. Invented, and labelled so.
filesmap of stringrequiredThe rule set it drafts to, ready for
POST /v1/policies.noteslist of stringrequired
- 401No API key was sent, or it is not in use (
unauthorized). - 403The caller may not do this, and
typesays why: the key or role lacks the scope, the rule set is not enabled for this account, the person signed in belongs to no account, names were asked for by a caller that is not shown them, or a request acting in test tried to change the account's settings (live-only). - 422The request, or a fact in it, is not in the documented shape - a query parameter the operation does not take included, which is named (
unknown_parameter) rather than ignored - or itsHimmel-Envdoes not fit the caller. Missing facts are not errors. - 429More requests in a minute than the key's or the person's limit (
rate-limited) - or, opening an account, more accounts in a day than the deployment opens, withRetry-Aftersaying when to try again. - 500Something failed on our side.
X-Request-Ididentifies it in our logs.