Documentation ▸

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, or default for the documented defaults your matching rules start from);
  • its worked examples, each as one sentence;
  • 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;
  • 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_confirmation or rule_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

GET/v1/confirmationsScope rules:read

What 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 ConfirmationSetrequired
    5 fields
    • rule_setstringrequired
    • kindstringrequired

      law, policy or matching.

    • domainstringrequired
    • titlestringrequired
    • versionslist of ConfirmationVersionrequired
      7 fields
      • versionstringrequired
      • statusstringrequired

        draft, published or superseded.

      • effective_fromstringrequired
      • rulesintegerrequired

        How many rules the version has.

      • pendingintegerrequired

        How many nobody has confirmed or flagged yet.

      • flaggedintegerrequired

        How many your rule owner flagged. A flagged rule stays off.

      • waitingintegerrequired

        How 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 type says 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 its Himmel-Env does 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, with Retry-After saying when to try again.
  • 500Something failed on our side. X-Request-Id identifies it in our logs.
GET/v1/confirmations/{rule_set}/{version}Scope rules:read

One 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 · stringrequired
  • versionpath · stringrequired

Responses

200 Successful response
  • rule_setstringrequired
  • versionstringrequired
  • statusstringrequired
  • effective_fromstringrequired
  • pendingintegerrequired

    How many rules still wait for your rule owner.

  • waitingintegerrequired

    How many answers that stand wait on a rule of this version. Confirming what is pending checks them again.

  • ruleslist of PageRulerequired
    10 fields
    • rulestringrequired
    • stagestringrequired
    • titlestringrequired
    • wordingstringrequired
    • rule_hashstringrequired

      A confirmation binds to this hash; a changed rule is confirmed again.

    • status"pending" | "confirmed" | "flagged" | "carried_over"required

      pending: nobody has confirmed or flagged it. confirmed on 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.

    • waitingintegerrequired

      How many answers that stand stopped at this rule: it is the first they could not pass, unconfirmed or flagged.

    • citationslist of PageCitationrequired
      8 fields
      • sourcestringrequired
      • paragraphstring or null
      • clausestring or null
      • text_refstring or null
      • source_titlestring or null
      • source_kindstring or null

        statute, official_guidance, case, policy_document, or default: the documented defaults a matching rule set starts from.

      • excerptstring or null

        The passage itself, as the rule set holds it.

      • anchors_availablelist of string or null

        Where the citation resolves to no passage: the anchors the source has.

    • exampleslist of WorkedExamplerequired
      3 fields
      • casestringrequired
      • examplestringrequired

        The case as one sentence, for the owner to read.

      • sourceobject or null

        What settles the case: its type and reference.

    • decisionDecision or null
      5 fields
      • action"confirmed" | "flagged"required
      • atstringrequired
      • versionstringrequired

        The 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 null
      • commentstring 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 type says 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 its Himmel-Env does 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, with Retry-After saying when to try again.
  • 500Something failed on our side. X-Request-Id identifies it in our logs.
POST/v1/confirmations/{rule_set}/{version}Scope confirm

Confirm, 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 · stringrequired
  • versionpath · stringrequired
  • Idempotency-Keyheader · string or null

    Makes 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 ConfirmationItemrequired
    3 fields
    • rulestringrequired
    • action"confirm" | "flag"required
    • commentstring
  • by_userstring or null

    Who 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_setstringrequired
  • versionstringrequired
  • recordedlist of Recordedrequired
    3 fields
    • rulestringrequired
    • action"confirmed" | "flagged"required
    • rule_hashstringrequired
  • pendinglist of stringrequired

    Rules of this version still waiting.

  • rerun_idstring or null

    The re-run that checks again, in the background, every answer this decision may change. Its checks.rerun alert says what changed, and GET /v1/checks?rerun= lists them. Null for matching rules, which match recipients again instead.

  • drafting_againDraftingAgain or null

    The 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_idstringrequired

      The document they were drafted from, which says drafting and where while they are drafted again, then what came of each in its latest entry of drafts.

    • job_idstringrequired
    • ruleslist of stringrequired
  • 401No API key was sent, or it is not in use (unauthorized).
  • 403The caller may not do this, and type says 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 its Himmel-Env does 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, with Retry-After saying when to try again.
  • 500Something failed on our side. X-Request-Id identifies it in our logs.
GET/v1/rules/{rule_set}/{version}/diffReadable without a key

What 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 · stringrequired
  • versionpath · stringrequired
  • fromquery · stringrequired

Responses

200 Successful response
  • fromVersionRefrequired
    2 fields
    • rule_setstringrequired
    • versionstringrequired
  • toVersionRefrequired
    2 fields
    • rule_setstringrequired
    • versionstringrequired
  • summaryDiffSummaryrequired
    4 fields
    • changedintegerrequired
    • addedintegerrequired
    • removedintegerrequired
    • unchangedintegerrequired
  • ruleslist of RuleChangerequired
    8 fields
    • rulestringrequired
    • status"changed" | "added" | "removed" | "unchanged"required
    • titlestringrequired
    • wording_beforestring or null
    • wording_afterstring or null
    • rule_hash_beforestring or null
    • rule_hash_afterstring or null
    • movedMoved or null

      For a rule changed, what moved in it beyond its words; null for any other.

      6 fields
      • titlebooleanrequired

        Whether its title changed.

      • wordingbooleanrequired

        Whether its words changed: wording_before and wording_after.

      • clauseslist of ClauseMovedrequired
        4 fields
        • sourcestringrequired
        • clausestringrequired

          Its clause or paragraph, as the rule cites it.

        • beforestring or null

          Its text before: null where the rule did not cite it, or it had none.

        • afterstring or null

          Its text now: null where the rule cites it no longer, or it has none.

      • exampleslist of ExampleMovedrequired
        7 fields
        • casestringrequired
        • factslist of FactMovedrequired

          The facts of it that moved.

        • answerbooleanrequired

          Whether the answer it expects moved.

        • historybooleanrequired

          Whether the earlier actions it counts moved.

        • otherbooleanrequired

          Whether anything else of it moved: who acts, the settings or decisions it assumes, its source.

        • beforestring or null

          Its sentence before: null for an example the rule did not have.

        • afterstring or null

          Its sentence now: null for one it has no longer.

      • logicbooleanrequired

        Whether its conditions, what each branch decides, what it requires or its place among the rules changed.

      • readslist of ReadMovedrequired
        3 fields
        • kind"fact" | "setting" | "derived" | "total" | "table"required
        • namestringrequired
        • changedlist of stringrequired

          What of it changed: new or gone; for a fact or a setting its type, values, pattern, currency, signed or approval (whether it records an approval); for a total its sum, where, group_by, window or days; for a derived value its expression; for a table its rows.

  • examples_changedlist of ExampleChangerequired
    5 fields
    • casestringrequired
    • examplestringrequired
    • beforeExampleResultrequired
      3 fields
      • statestringrequired
      • outcomestring or null
      • consequenceslist of KeyValue or null
        2 fields
        • keystringrequired
        • valueany
    • afterExampleResultrequired
      3 fields
      • statestringrequired
      • outcomestring or null
      • consequenceslist of KeyValue or null
        2 fields
        • keystringrequired
        • valueany
    • rulestring or null
  • 401No API key was sent, or it is not in use (unauthorized).
  • 403The caller may not do this, and type says 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 its Himmel-Env does 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, with Retry-After saying when to try again.
  • 500Something failed on our side. X-Request-Id identifies it in our logs.