Confirmations
Nothing runs for your account until your rule owner confirms it.
Nothing runs for your account until your rule owner has confirmed it. Every rule — of the law, of your own policies, of your matching rules — is written in plain language, cites the paragraph or clause it applies, and comes with worked examples. Your rule owner reads each one and confirms it, or flags it with a comment. Until then, a check that reaches the rule answers not_covered with the reason awaiting_confirmation.
There is no outside review step. Himmel is not a law firm and gives no advice: your company owns the decision to confirm a rule, and if you want a rule looked at, you take it to your own adviser.
What there is to confirm
GET /v1/confirmations lists every rule set your account has on, and each of its versions with what waits in it: how many rules it has, how many are pending — nobody has confirmed or flagged them — how many are flagged, and waiting, the answers that wait on it (below). The law comes first, then your policies, drafts included, then your matching rules. A rule set of the law is on once it is switched on for your account; until then it is not listed, and its page answers 403 rule-set-not-enabled, as a check naming it does.
The confirmation page
GET /v1/confirmations/{rule_set}/{version} is one page per rule set version. For each rule it gives:
- its
wording, the sentence your rule owner confirms; - every citation, with the passage it points at (
excerpt) and what kind of source that is (source_kind:statute,official_guidance,case,policy_document, ordefaultfor the documented defaults your matching rules start from); - its worked examples, each as one sentence;
- its
status:pending;confirmedon this page;flagged; orcarried_over, confirmed on another version's page where the rule reads exactly as it does here; - its
decision, once there is one: confirmed or flagged, by whom, when, and on which version's page (version); waiting: how many of your answers stopped at this rule, the first they could not pass.
The page's own waiting counts every answer that waits on a rule of this version — what confirming everything pending will check again. An answer names only the first rule it could not pass, so confirming that one may leave it waiting on the next; the page's figure is the one to read.
Confirming and flagging
curl https://api.gethimmel.com/v1/confirmations/de_gifts_entertainment/1.1.0 \
-H "Authorization: Bearer $HIMMEL_KEY" -H "Content-Type: application/json" \
-d '{ "by_user": "usr_01J9Q4TZ8M...",
"rules": [
{ "rule": "de_gifts_entertainment.gifts.limit", "action": "confirm" },
{ "rule": "de_gifts_entertainment.entertainment.documented", "action": "flag",
"comment": "We book restaurant invoices without the guest list; the list is on the expense report." }
] }'
Each confirmation binds to the rule's rule_hash. A rule whose wording, logic, citations or worked examples change has a new hash, and is confirmed again. A flagged rule stays off for your account — checks that reach it answer not_covered with the reason rule_flagged — and the comment reaches whoever maintains it: us, for a rule of the law; your policy's draft, for one of your own.
A rule of your own policy, drafted from its document and flagged with a comment, is drafted again by itself, in the background — a few minutes, not a new draft of the whole playbook. The response's drafting_again names the document it follows on (document_id), the job and the rules; it is null for a rule of the law or of your matching rules, a policy posted as files, a flag without a comment, or a deployment that drafts nothing. The rule is drafted again from the document and what you said - your comment masked, as the document is, so no name in it reaches the model - into your policy's draft, or into a draft of the next version where the flagged one is already switched on. It comes back to this page to be confirmed as it then reads, and every rule it did not touch keeps its confirmation. It is written only where nothing else moves: where drafting it again would change what an example of another rule comes out as, it is not written, the flag stands, and the document's latest entry in drafts says which examples it would have changed. Where your comment asks for what the document does not say, the rule comes back as the document says it: change the playbook itself by revising its document (Policies).
by_user is the Himmel id of the person confirming, which the console shows them on its Developers page, and every colleague's on Settings' People page. It has to be an admin of your account, because only an admin confirms; a name, or anybody else's id, is refused. The confirmation records that person, and the record of the request also keeps which key sent it: a key can only claim who it acts for. Signed in to the console, you confirm as yourself and leave by_user out.
What confirming checks again
Every answer your rule owner's decision may change is checked again, in the background, in live and test alike — the response's rerun_id names this re-run:
- answers that waited on the owner:
not_covered,awaiting_confirmationorrule_flagged; - answers that used a rule the owner has now flagged;
- answers given under an earlier version of the rule set, or without a policy that now applies to their date.
An answer that moved is issued again as a new check that replaces it (supersedes_check_id, recheck_reason: rerun); the earlier one is kept, unchanged. Several decisions in a row check each answer again once. When the re-run is done, one checks.rerun alert says how many answers were issued again and how many changed state or outcome, and GET /v1/checks?rerun={rerun_id} lists them. A proposal nobody has reported as executed is left as it was answered: ask again — or report it done, which checks it again as it then stands.
So the order of the first steps does not matter: send your bookings before the rules are confirmed, and confirming them afterwards answers them again. A flag applies at once: the answers that used the rule are issued again as not_covered, rule_flagged, and confirming the rule later issues them again.
New versions
When the law changes, a new version is published with the date it applies from, and your admins are told in an alert. Only the rules that changed are pending on its page: every rule whose hash did not change is carried_over from your earlier confirmation, and runs without being confirmed again. It works the other way too: confirm the newer version first, and the rules an older version shares with it read carried_over on the older version's page, with only the ones it words differently left pending.
GET /v1/rules/{rule_set}/{version}/diff?from={version} says what changed in the words your rule owner confirms in: each rule changed, added, removed or unchanged, its wording before and after, and every worked example that now comes out differently. The examples are run under both versions, not compared as text — "these four examples now answer differently" is what makes a change readable.
A rule can change in none of its own words: the clause it cites is reworded, its worked examples move with a figure they are worked out from, a fact it reads now records an approval. It is confirmed again all the same, so each rule changed says what moved in it - moved: whether its title and wording changed; clauses, each passage it cites that reads otherwise now, before and after; examples, each worked example that changed, its sentence before and after and the facts that moved, and whether the answer it expects, its history or anything other moved; logic, whether its conditions or what it decides changed; and reads, each fact, setting, value, total or table it reads whose definition changed, and what of it. The console shows it under the rule.
Until the changed rules are confirmed, a transaction that falls under the new version and reaches one of them answers not_covered with awaiting_confirmation. Once the version applies and answers for actions taken wait on rules of it still unconfirmed, a confirmation.overdue alert says how many.
A version nobody has confirmed takes no answer away. The answers you were given under the earlier version stand until your rule owner confirms the changed rules; then each is checked again under the new version, with one checks.rerun alert for all of them. A new version with nothing left to confirm — every rule carried over — answers them again as soon as it is published. The same holds for a policy of your own: published, it applies to your earlier answers once its rules are confirmed.
Endpoints
/v1/confirmationsScope rules:readWhat your account has to confirm
Every version of every rule set your account has on - our law where it is switched on for your account, your own policies, drafts included, and your matching rules - with how many of each version's rules wait for your rule owner (pending), how many they flagged, and waiting: how many answers that stand wait on a rule of the version, which confirming issues again. Law comes first, then policies, then matching rules, each oldest version first. A version's own page is GET /v1/confirmations/{rule_set}/{version}.
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
rule_setslist of ConfirmationSetrequired5 fields
rule_setstringrequiredkindstringrequiredlaw,policyormatching.domainstringrequiredtitlestringrequiredversionslist of ConfirmationVersionrequired7 fields
versionstringrequiredstatusstringrequireddraft,publishedorsuperseded.effective_fromstringrequiredrulesintegerrequiredHow many rules the version has.
pendingintegerrequiredHow many nobody has confirmed or flagged yet.
flaggedintegerrequiredHow many your rule owner flagged. A flagged rule stays off.
waitingintegerrequiredHow many answers that stand wait on a rule of this version.
- 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/confirmations/{rule_set}/{version}Scope rules:readOne page per rule set version: what to confirm, and what carried over
Nothing runs for your account until your rule owner confirms it. Per rule: its wording, each citation with the passage it points at, its worked examples as sentences, and its status - pending, confirmed on this page, flagged, or carried_over: confirmed on another version's page, where the rule reads exactly as it does here, so it runs without being confirmed again; its decision names that version. waiting counts the answers that stand and wait on a rule of this version, which confirming it issues again; each rule's waiting counts those that stopped at that rule, the first they could not pass. A rule set of the law is your account's to read and confirm once it is switched on for your account: before, this is rule-set-not-enabled.
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
rule_setpath · stringrequiredversionpath · stringrequired
Responses
200 Successful response
rule_setstringrequiredversionstringrequiredstatusstringrequiredeffective_fromstringrequiredpendingintegerrequiredHow many rules still wait for your rule owner.
waitingintegerrequiredHow many answers that stand wait on a rule of this version. Confirming what is pending checks them again.
ruleslist of PageRulerequired10 fields
rulestringrequiredstagestringrequiredtitlestringrequiredwordingstringrequiredrule_hashstringrequiredA confirmation binds to this hash; a changed rule is confirmed again.
status"pending" | "confirmed" | "flagged" | "carried_over"requiredpending: nobody has confirmed or flagged it.confirmedon this page.flagged: it stays off.carried_over: confirmed on another version's page, where it reads exactly as here, so it runs without being confirmed again.waitingintegerrequiredHow many answers that stand stopped at this rule: it is the first they could not pass, unconfirmed or flagged.
citationslist of PageCitationrequired8 fields
sourcestringrequiredparagraphstring or nullclausestring or nulltext_refstring or nullsource_titlestring or nullsource_kindstring or nullstatute,official_guidance,case,policy_document, ordefault: the documented defaults a matching rule set starts from.excerptstring or nullThe passage itself, as the rule set holds it.
anchors_availablelist of string or nullWhere the citation resolves to no passage: the anchors the source has.
exampleslist of WorkedExamplerequired3 fields
casestringrequiredexamplestringrequiredThe case as one sentence, for the owner to read.
sourceobject or nullWhat settles the case: its type and reference.
decisionDecision or null5 fields
action"confirmed" | "flagged"requiredatstringrequiredversionstringrequiredThe version on whose page this was decided. Where it is another version's, the rule reads there exactly as it does here, and the decision holds for both.
by_userstring or nullcommentstring or null
previous_versionstring 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/confirmations/{rule_set}/{version}Scope confirmConfirm, or flag, per rule
Each confirmation binds to the rule's hash, so a rule that changes is confirmed again. A flagged rule stays off for your account - checks that reach it answer not_covered with rule_flagged - and the comment reaches whoever maintains it: us for a rule of the law, your policy's draft for one of yours. Every answer your decision may change is checked again, in the background and in live and test alike: answers that waited on these rules, answers that used a rule you flag, and answers given under an earlier version this one now governs. rerun_id names that re-run; its checks.rerun alert says what changed. A rule of your policy that was drafted from its document, flagged with a comment, is drafted again alone, in the background: drafting_again names the document it follows on, the job and the rules, and the rule comes back to this page to be confirmed as it then reads, every rule it did not touch keeping its confirmation. A rule set of the law is confirmed once it is switched on for your account: before, this is rule-set-not-enabled, and nothing is recorded.
Needs a key with the scope confirm. 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
rule_setpath · stringrequiredversionpath · 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
ruleslist of ConfirmationItemrequired3 fields
rulestringrequiredaction"confirm" | "flag"requiredcommentstring
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
rule_setstringrequiredversionstringrequiredrecordedlist of Recordedrequired3 fields
rulestringrequiredaction"confirmed" | "flagged"requiredrule_hashstringrequired
pendinglist of stringrequiredRules of this version still waiting.
rerun_idstring or nullThe re-run that checks again, in the background, every answer this decision may change. Its
checks.rerunalert says what changed, andGET /v1/checks?rerun=lists them. Null for matching rules, which match recipients again instead.drafting_againDraftingAgain or nullThe rules of your policy flagged with a comment, drafted again alone from its document and what you said. Null where none is: a rule of the law or of the matching rules, a policy posted as files, a flag without a comment, or a deployment that drafts nothing.
3 fields
document_idstringrequiredThe document they were drafted from, which says
draftingand where while they are drafted again, then what came of each in its latest entry ofdrafts.job_idstringrequiredruleslist 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). - 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/rules/{rule_set}/{version}/diffReadable without a keyWhat changed, in the words the owner confirms in
Per rule: changed, added, removed or unchanged, with the wording before and after. Then the worked examples that come out differently: each is run under both versions, not compared as text. Only changed and added rules need confirming again, and a rule changed says what moved in it beyond its own words (moved): a clause it cites, its examples, what it reads.
Readable without a key, for the rule sets of the law; with one, it needs the scope rules:read, and your own rule sets are added - except for a key made for an agent, which reads it as anybody does: what its agent is held to is GET /v1/agents/{agent_id}/rules.
Parameters
rule_setpath · stringrequiredversionpath · stringrequiredfromquery · stringrequired
Responses
200 Successful response
fromVersionRefrequired2 fields
rule_setstringrequiredversionstringrequired
toVersionRefrequired2 fields
rule_setstringrequiredversionstringrequired
summaryDiffSummaryrequired4 fields
changedintegerrequiredaddedintegerrequiredremovedintegerrequiredunchangedintegerrequired
ruleslist of RuleChangerequired8 fields
rulestringrequiredstatus"changed" | "added" | "removed" | "unchanged"requiredtitlestringrequiredwording_beforestring or nullwording_afterstring or nullrule_hash_beforestring or nullrule_hash_afterstring or nullmovedMoved or nullFor a rule
changed, what moved in it beyond its words; null for any other.6 fields
titlebooleanrequiredWhether its title changed.
wordingbooleanrequiredWhether its words changed:
wording_beforeandwording_after.clauseslist of ClauseMovedrequired4 fields
sourcestringrequiredclausestringrequiredIts clause or paragraph, as the rule cites it.
beforestring or nullIts text before: null where the rule did not cite it, or it had none.
afterstring or nullIts text now: null where the rule cites it no longer, or it has none.
exampleslist of ExampleMovedrequired7 fields
casestringrequiredfactslist of FactMovedrequiredThe facts of it that moved.
answerbooleanrequiredWhether the answer it expects moved.
historybooleanrequiredWhether the earlier actions it counts moved.
otherbooleanrequiredWhether anything else of it moved: who acts, the settings or decisions it assumes, its source.
beforestring or nullIts sentence before: null for an example the rule did not have.
afterstring or nullIts sentence now: null for one it has no longer.
logicbooleanrequiredWhether its conditions, what each branch decides, what it requires or its place among the rules changed.
readslist of ReadMovedrequired3 fields
kind"fact" | "setting" | "derived" | "total" | "table"requirednamestringrequiredchangedlist of stringrequiredWhat of it changed:
neworgone; for a fact or a setting itstype,values,pattern,currency,signedorapproval(whether it records an approval); for a total itssum,where,group_by,windowordays; for a derived value itsexpression; for a table itsrows.
examples_changedlist of ExampleChangerequired5 fields
casestringrequiredexamplestringrequiredbeforeExampleResultrequired3 fields
statestringrequiredoutcomestring or nullconsequenceslist of KeyValue or null2 fields
keystringrequiredvalueany
afterExampleResultrequired3 fields
statestringrequiredoutcomestring or nullconsequenceslist of KeyValue or null2 fields
keystringrequiredvalueany
rulestring 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.