Accounts for your customers
Your agents act for your customers: an account for each, its owner confirming its playbook, your agents' keys there.
If your agents act for your customers - an AI support agent for online shops, say - open an account on Himmel for each customer you serve. It is your customer's account: its playbook, and the record of every action your agents take there, are theirs whatever becomes of you. The person who runs it, its owner, confirms its rules, names who approves and approves where its rules name them. You act in it as its builder, and no further.
Himmel answers; your agent's tools enforce. In your customer's account Himmel checks your agent against your customer's own rules, and keeps the proof for them.
What you do there, and what you never do
| You | You never |
|---|---|
| open the account, with its owner's address and your agents | confirm a rule, or switch a playbook on |
| register your agents there, and make and revoke their keys | change a setting, or name who approves |
| send its owner's invitation again, until they join | invite anybody but its owner |
| post its playbook from Himmel's template, or fill a draft of it again | decide a question, or approve an action |
| read where it stands | see its customers' names, or hold a key that confirms |
The account has no keys of its own: every key you hold there is one of your agents', which asks, reports and reads its rules, and none of them confirms a rule in its owner's name.
Before you start
Your company's own account, opened by signing up: see Opening your account. Opening an account for a customer, and everything you do in one, is a person's work - an admin or an engineer of your account, signed in to the console, under Developers, Your customers' accounts; or through the API with their session. No key opens an account or makes a key: the scope it needs, accounts, belongs to people alone. The sandbox opens none.
Open an account
POST /v1/accounts opens one:
{
"account": {
"name": "Example Coffee GmbH",
"slug": "example_coffee",
"country": "DE",
"currency": "EUR",
"retention_years": 10
},
"owner": { "email": "owner@coffee.example" },
"agents": [{ "id": "agt_support", "role": "The support assistant" }],
"playbook": {
"template": "online_shop_support",
"values": {
"refund_without_approval": { "amount": 5000, "currency": "EUR" },
"refund_with_team_lead": { "amount": 25000, "currency": "EUR" },
"refund_by_assistant": { "amount": 3000, "currency": "EUR" },
"refund_days": 30,
"discount_without_approval": 15,
"discount_with_team_lead": 30,
"credit_at_most": { "amount": 2000, "currency": "EUR" },
"credits_in_window": 2,
"credit_window_days": 90,
"credits_a_year": { "amount": 6000, "currency": "EUR" },
"refund_above_assistant": "hand_to_a_person"
}
}
}
- The account is your customer's company, as you open your own: its name; a short name of 2 to 40 lower-case letters, digits and
_, which names its rule sets (policy.example_coffee.customer_support); where it is established; the currency its books are kept in, never taken from the country; and how many years its country's law has it keep its records, from 1 to 30. - Its owner is the address of the person who runs it. Never somebody in your own account: one person is in one account, and they could not join it.
- Your agents that act for it, up to ten, each by its id in your systems and what it is, in words.
- Its playbook, where you have the customer's figures: Himmel's template for an online shop's support - refunds, retention discounts and goodwill credits - with every figure filled in, money in the account's currency, and its one choice made - what becomes of a refund above what the AI assistant gives on its own: handed to the team lead, whom Himmel tells (
hand_to_a_person), or the team lead's approval first (team_lead_approval). Himmel proposes none.GET /v1/templateslists each blank, what it is, the clauses that say it and the least and most it takes, and each choice with its options; a figure out of the order its words put them in is refused, naming the clauses. Leaveplaybookout to post it later.
The answer is the account, where it stands, and each of your agents' keys there, a live one and a test one, shown once: store each where that agent reads its secrets. A retry with the same Idempotency-Key gets the same answer with every key empty, never a second account.
Refused, with nothing opened: a field not as described (422, naming it), a short name another account has (409, taken), an owner's address of your own people (422, in_your_account), the sandbox (409), and the accounts opened in a day - 20 by your account, 5 from one network address, 50 for all of Himmel (429 rate-limited, with Retry-After saying in how many seconds the next can be opened).
Its owner joins
Himmel emails the owner - not you: who opened the account for whom, what waits for them, and the link that signs them up at the address you gave. You never see that link: whoever holds it joins as the account's owner. Signed up, they accept Himmel's terms for their account and go straight to their playbook: each rule beside the clause it comes from, in their figures; a figure that is not theirs changed there, the playbook filled again from the template; who approves, and the day their year starts; and one button that confirms the rules and switches the playbook on. Nothing in the account answers until they do. They own your agents there from then, and switch any of them off in one step.
Where each stands
GET /v1/accounts lists the accounts you opened, the newest first, fifty to a page - limit up to 200, and before set to the last page's next_before for the next. Each says:
| Field | What it says |
|---|---|
owner | their invitation: waiting, accepted once they joined, or expired - send it again; when it runs out, and when Himmel's email went (emailed_at; still null a few minutes on, their mail server may have refused the address - send it again, to one it takes) |
terms | Himmel's terms, as the owner accepted them for the account |
playbooks | each playbook's version its owner switched on, and the draft waiting for them |
agents | your agents there: whether each is switched off, and when each last acted, in live |
cut_off_at | when its owner cut you off: every other field is then empty |
GET /v1/accounts/{account_id} reads one, with the owner's address while their invitation waits - the address you send it again from - and the keys you made there, never the keys themselves. Never the account's own agents or people, its customers, or what its people decided.
Your agents and their keys there
| Request | What it does |
|---|---|
POST /v1/accounts/{account_id}/agents | registers another of your agents there, by id and role |
POST /v1/accounts/{account_id}/keys | makes one of them a key, live or test, shown once |
POST /v1/accounts/{account_id}/keys/{key_id}/revoke | revokes one you made, for good |
A key acts in its customer's account alone. Your agent holds one key for each customer it serves, and asks with the key of the customer it is acting for, naming that customer's playbook by its short name: The SDK and Connect an agent by MCP show how. Every check it sends there is recorded in that customer's account, as your agent's, and its owner sees it in their check log.
The invitation again, and the playbook
| Request | What it does |
|---|---|
POST /v1/accounts/{account_id}/invitation | sends the owner's invitation again - to the same address, or a corrected one - until they have joined: the earlier link stops working. After that its people are theirs to invite (409, owner_joined) |
POST /v1/accounts/{account_id}/policies | posts its playbook from the template with your figures, as a draft its owner confirms rule by rule - the next version, where one is switched on. A draft of it already there is 409: fill that again |
PUT /v1/accounts/{account_id}/policies/{policy_id} | fills its draft again with every figure: the rules a changed figure reaches wait for its owner again |
Never a playbook's files, and never switched on: its owner does that.
When its owner cuts you off
The owner, or another admin of their account, can cut you off - from then, and for good. Every request you make in that account is 403 cut-off, and where it stands reads as what it is and when, and nothing more. Your agents there act on until its owner switches them off or revokes their keys: an owner who wants your agent to stop switches it off.
When a request is refused
| Status | Problem type | Why |
|---|---|---|
| 403 | insufficient-scope | A key, or a role that does not hold accounts - opening and acting in your customers' accounts is an admin's or an engineer's, signed in |
| 403 | cut-off | The account's owner cut you off |
| 403 | live-only | A change made from test: your customers' accounts are changed from your own account's live side |
| 404 | not-found | An account your account did not open, or a key you did not make there |
| 409 | conflict | A short name taken, an agent registered there already, the owner joined, a draft of the playbook there already, or the sandbox |
| 422 | invalid-request | A field not as described, naming it, or an owner's address of your own people |
| 503 | sign-in-unavailable | Clerk, which signs people in, could not be asked: nothing was opened or sent |
| 503 | sign-up-closed | Accounts are opened once Himmel's terms are published: nothing was opened |
Endpoints
/v1/accountsScope accountsThe accounts you opened for your customers
The accounts your account opened for the customers its agents serve, the newest first, fifty to a page, each with where it stands: its owner invited or joined - their address is one account's read - the terms they accepted for it, each playbook's version switched on and its draft waiting, and your agents there - switched off or not, and when each last acted, in live. Never the account's own agents or people, its customers, or what its people decided. Of one its owner cut you off from, what it is and when, and nothing more. Continue with before set to the last page's next_before.
Needs a person signed in whose role carries accounts: no key can hold it.
Parameters
limitquery · integerHow many accounts to a page.
beforequery · string or nullThe last page's
next_before, an account's id, to continue from.
Responses
200 Successful response
accountslist of OpenedAccountrequiredThe accounts your account opened for its customers, the newest first, a page.
13 fields
idstringrequiredslugstringrequirednamestringrequiredcountrystringrequiredcurrencystringrequiredretention_yearsintegerrequiredopened_atstringrequiredcut_off_atstring or nullWhen its owner cut you off from it, for good: you act in it no more, and read nothing more of it. Your agents there act on until its owner switches them off. Null while you may act.
ownerOpenedOwner or nullIts owner. Null once you were cut off.
6 fields
status"waiting" | "accepted" | "withdrawn" | "expired"requiredwaitingfor them to take it up;accepted, they joined - the account is theirs to run;expired, not taken up in time - send it again.invited_atstringrequiredexpires_atstringrequiredemailstring or nullThe address you sent it to, while it waits, to send it again from - or to another: in one account's read (
GET /v1/accounts/{account_id}), and null in the list. Null once they have joined: their address is theirs.emailed_atstring or nullWhen Himmel's email with the invitation's link went to them: who opened the account for whom, what waits for them, and the link, which you never see. Null until it has gone, and where their mail server refused the address - send it again, to one it takes - and where the deployment sends no email of its own, when Clerk sent its own.
joined_atstring or nullWhen they joined. Null until they have.
termsOpenedTerms or nullHimmel's terms, as its owner accepted them for it joining. Null until they have.
2 fields
versionstringrequiredaccepted_atstringrequired
playbookslist of OpenedPlaybook or nullIts playbooks, by rule set. Null once you were cut off.
4 fields
rule_setstringrequiredtitlestringrequiredswitched_onSwitchedOnVersion or nullThe latest version its owner confirmed and switched on. Null while none is.
2 fields
versionstringrequiredeffective_fromstringrequiredThe day its owner switched it on from.
draftDraftVersion or nullThe draft waiting for its owner to confirm it, rule by rule. Null where none waits.
2 fields
policy_idstringrequiredThe draft's id: what
PUT /v1/accounts/{account_id}/policies/{policy_id}fills again.versionstringrequired
agentslist of OpenedAgent or nullYour agents there, in the order registered - never its own. Null once cut off.
5 fields
idstringrequiredregistered_atstringrequiredrolestring or nullswitched_off_atstring or nullWhen the account's owner - or a person they let - switched it off: every request its keys send there is refused since. Null while it is on.
last_acted_atstring or nullWhen an action recorded as its was last asked about or taken there, in live.
keyslist of OpenedKey or nullThe keys you made there, the newest first, revoked ones too: in one account's answer, null in the list of them and once you were cut off.
8 fields
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredlast_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
next_beforestring or nullbeforefor the next page, an account's id; null on the last.
- 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/accountsScope accountsOpen an account for a customer
For a builder - a company whose agents act for its customers: an admin or an engineer of its account opens one for a customer it serves. The account is the customer's: its account as POST /v1/me/account takes one; owner.email, the address of the person who runs it - who confirms its rules, names who approves and approves where its rules name them - invited at once; agents, yours that act for it, each by id and role, registered there and owned by the owner once they join; and playbook, where you have its figures, a template filled with them (GET /v1/templates), posted as a draft its owner confirms. It opens with live and test and no keys of its own: nothing you hold confirms a rule in its owner's name. Each of your agents gets a live and a test key, an agent's four scopes, each shown here once. From then you read where it stands, register your agents there and make and revoke their keys, send its owner's invitation again and post its playbook from a template - nothing more: never a confirmation, a playbook switched on, a setting, a person, a decision or an approval. Its owner joins accepting Himmel's terms for it, and may cut you off. Refused, nothing opened: a field not as described (422, naming it - account.<field>, owner.email, agents[i].id, playbook.values.<blank>), a company name holding an email address or an IBAN (422 pii-in-facts), an owner's address of a person in your own account (422, in_your_account: they cannot join another), a slug taken (409, taken), the sandbox (409, test_only_account), the accounts opened in a day - 20 by one builder, 5 from one network address, 50 for the whole deployment (429 rate-limited, with Retry-After saying when to try again) - Clerk not answering (503 sign-in-unavailable), and a deployment whose terms are not yet written (503 sign-up-closed). A retry with the same Idempotency-Key gets the same answer, the keys' key and the owner's email null.
Needs a person signed in whose role carries accounts: no key can hold it. 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
accountAccountFieldsrequired5 fields
namestringrequiredThe company's name, as every page of the console shows it: one line, up to 200 characters, never an email address or an IBAN (
pii-in-facts).slugstringrequiredThe account's short name, which names its own rule sets -
policy.<slug>.<name>- so it is 2 to 40 lower-case letters, digits and_, beginning with a letter, and one account's alone (409,taken).countrystring, one of 249requiredWhere the company is established, as an ISO 3166-1 code:
US,AE,DE- the United Kingdom isGB. Never read off the currency.currencystring, one of 165requiredThe currency the company's books are kept in, as an ISO 4217 code amounts are written in:
USD,AED,EUR. Never taken from the country: a company may keep its books in another.retention_yearsintegerrequiredHow many years the company must keep its records - its country's law, which it says, from 1 to 30 - and so how long Himmel keeps every check of the account. Never assumed.
ownerOwnerBodyrequired1 field
emailstringrequiredThe address the owner signs in with. They are emailed an invitation to the account, and join it signed up at that address. Never a person of your own account, who cannot join another (
in_your_account).
agentslist of OpenedAgentBodyYour agents that act for it, each by its id and role - up to ten; more are registered later. Each gets a live and a test key, made for you.
2 fields
idstringrequiredThe agent's own id in your systems - what every check it sends records, and what a rule reading
actor.idnames: letters, digits and_ . : -, up to 64, never a name or an address, and never beginningusr_. Fixed once registered.rolestringrequiredWhat the agent is, in words, as every page names it:
The support assistant. One line; never a person's name or address (pii-in-facts).
playbookPlaybookBody or nullIts playbook, where you have its figures: posted as a draft its owner confirms. Left out, it is posted later (
POST /v1/accounts/{account_id}/policies).2 fields
templatestringrequiredOne of our templates, by its name (
GET /v1/templates).valuesobjectrequiredEvery blank of the template and your figure for it, by the blank's name: money as an integer
amountin minor units with the 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, and its owner confirms each rule with its figure, or changes it.
Responses
200 Successful response
accountOpenedAccountrequired13 fields
idstringrequiredslugstringrequirednamestringrequiredcountrystringrequiredcurrencystringrequiredretention_yearsintegerrequiredopened_atstringrequiredcut_off_atstring or nullWhen its owner cut you off from it, for good: you act in it no more, and read nothing more of it. Your agents there act on until its owner switches them off. Null while you may act.
ownerOpenedOwner or nullIts owner. Null once you were cut off.
6 fields
status"waiting" | "accepted" | "withdrawn" | "expired"requiredwaitingfor them to take it up;accepted, they joined - the account is theirs to run;expired, not taken up in time - send it again.invited_atstringrequiredexpires_atstringrequiredemailstring or nullThe address you sent it to, while it waits, to send it again from - or to another: in one account's read (
GET /v1/accounts/{account_id}), and null in the list. Null once they have joined: their address is theirs.emailed_atstring or nullWhen Himmel's email with the invitation's link went to them: who opened the account for whom, what waits for them, and the link, which you never see. Null until it has gone, and where their mail server refused the address - send it again, to one it takes - and where the deployment sends no email of its own, when Clerk sent its own.
joined_atstring or nullWhen they joined. Null until they have.
termsOpenedTerms or nullHimmel's terms, as its owner accepted them for it joining. Null until they have.
2 fields
versionstringrequiredaccepted_atstringrequired
playbookslist of OpenedPlaybook or nullIts playbooks, by rule set. Null once you were cut off.
4 fields
rule_setstringrequiredtitlestringrequiredswitched_onSwitchedOnVersion or nullThe latest version its owner confirmed and switched on. Null while none is.
2 fields
versionstringrequiredeffective_fromstringrequiredThe day its owner switched it on from.
draftDraftVersion or nullThe draft waiting for its owner to confirm it, rule by rule. Null where none waits.
2 fields
policy_idstringrequiredThe draft's id: what
PUT /v1/accounts/{account_id}/policies/{policy_id}fills again.versionstringrequired
agentslist of OpenedAgent or nullYour agents there, in the order registered - never its own. Null once cut off.
5 fields
idstringrequiredregistered_atstringrequiredrolestring or nullswitched_off_atstring or nullWhen the account's owner - or a person they let - switched it off: every request its keys send there is refused since. Null while it is on.
last_acted_atstring or nullWhen an action recorded as its was last asked about or taken there, in live.
keyslist of OpenedKey or nullThe keys you made there, the newest first, revoked ones too: in one account's answer, null in the list of them and once you were cut off.
8 fields
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredlast_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
keyslist of OpenedKeyMaderequiredFor each of your agents, in the order sent, its live key and then its test key - each an agent's four scopes.
keyis each one itself, shown here once: store them now. A retry with the sameIdempotency-Keygets their records withkeynull, and the owner's address null.9 fields
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredkeystring or nullrequiredThe key itself,
hk_live_…orhk_test_…: shown here once and never again. Null on a retry with the sameIdempotency-Key.last_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
- 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. - 503An optional part of the service is not configured in this deployment, or a service it relies on did not answer:
typesays which.
/v1/accounts/{account_id}Scope accountsAn account you opened, where it stands
One account your account opened, as GET /v1/accounts lists it, with its owner's address while their invitation waits - the one you send it again from - and the keys you made there: their records, never the keys. 404 not-found for one it did not open.
Needs a person signed in whose role carries accounts: no key can hold it.
Parameters
account_idpath · stringrequired
Responses
200 Successful response
idstringrequiredslugstringrequirednamestringrequiredcountrystringrequiredcurrencystringrequiredretention_yearsintegerrequiredopened_atstringrequiredcut_off_atstring or nullWhen its owner cut you off from it, for good: you act in it no more, and read nothing more of it. Your agents there act on until its owner switches them off. Null while you may act.
ownerOpenedOwner or nullIts owner. Null once you were cut off.
6 fields
status"waiting" | "accepted" | "withdrawn" | "expired"requiredwaitingfor them to take it up;accepted, they joined - the account is theirs to run;expired, not taken up in time - send it again.invited_atstringrequiredexpires_atstringrequiredemailstring or nullThe address you sent it to, while it waits, to send it again from - or to another: in one account's read (
GET /v1/accounts/{account_id}), and null in the list. Null once they have joined: their address is theirs.emailed_atstring or nullWhen Himmel's email with the invitation's link went to them: who opened the account for whom, what waits for them, and the link, which you never see. Null until it has gone, and where their mail server refused the address - send it again, to one it takes - and where the deployment sends no email of its own, when Clerk sent its own.
joined_atstring or nullWhen they joined. Null until they have.
termsOpenedTerms or nullHimmel's terms, as its owner accepted them for it joining. Null until they have.
2 fields
versionstringrequiredaccepted_atstringrequired
playbookslist of OpenedPlaybook or nullIts playbooks, by rule set. Null once you were cut off.
4 fields
rule_setstringrequiredtitlestringrequiredswitched_onSwitchedOnVersion or nullThe latest version its owner confirmed and switched on. Null while none is.
2 fields
versionstringrequiredeffective_fromstringrequiredThe day its owner switched it on from.
draftDraftVersion or nullThe draft waiting for its owner to confirm it, rule by rule. Null where none waits.
2 fields
policy_idstringrequiredThe draft's id: what
PUT /v1/accounts/{account_id}/policies/{policy_id}fills again.versionstringrequired
agentslist of OpenedAgent or nullYour agents there, in the order registered - never its own. Null once cut off.
5 fields
idstringrequiredregistered_atstringrequiredrolestring or nullswitched_off_atstring or nullWhen the account's owner - or a person they let - switched it off: every request its keys send there is refused since. Null while it is on.
last_acted_atstring or nullWhen an action recorded as its was last asked about or taken there, in live.
keyslist of OpenedKey or nullThe keys you made there, the newest first, revoked ones too: in one account's answer, null in the list of them and once you were cut off.
8 fields
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredlast_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
- 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/accounts/{account_id}/agentsScope accountsRegister one of your agents in an account you opened
Your agent, known there before it acts: id and role as POST /v1/agents takes them - an id the account has registered already is 409, already_registered. Its owner is the account's owner where they have joined, and nobody until they do. Make its keys with POST /v1/accounts/{account_id}/keys. 404 not-found for an account yours did not open, 403 cut-off for one whose owner cut you off.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_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
idstringrequiredThe agent's own id in your systems - what every check it sends records, and what a rule reading
actor.idnames: letters, digits and_ . : -, up to 64, never a name or an address, and never beginningusr_. Fixed once registered.rolestringrequiredWhat the agent is, in words, as every page names it:
The support assistant. One line; never a person's name or address (pii-in-facts).
Responses
200 Successful response
idstringrequiredregistered_atstringrequiredrolestring or nullswitched_off_atstring or nullWhen the account's owner - or a person they let - switched it off: every request its keys send there is refused since. Null while it is on.
last_acted_atstring or nullWhen an action recorded as its was last asked about or taken there, in live.
- 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/accounts/{account_id}/keysScope accountsMake a key for one of your agents in an account you opened
A key for one of your agents there, live or test, holding an agent's four scopes - check, checks:read, checks:write, rules:read - and never more: every check it sends records the agent. The key itself is in this answer and never again. An agent you did not register in that account is 422, unknown_agent. A retry with the same Idempotency-Key gets the same key's record, key null. 404 not-found for an account yours did not open, 403 cut-off for one whose owner cut you off.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_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
agentstringrequiredThe agent, by the id you registered it under there:
unknown_agentfor one you did not register in that account.env"live" | "test"requiredWhere it acts.
namestring or nullWhat it is for, as the account's check log shows it beside its prefix. Left out, the agent's id and the environment. Never a person's name or address (
pii-in-facts).
Responses
200 Successful response
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredkeystring or nullrequiredThe key itself,
hk_live_…orhk_test_…: shown here once and never again. Null on a retry with the sameIdempotency-Key.last_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
- 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/accounts/{account_id}/keys/{key_id}/revokeScope accountsRevoke a key you made in an account you opened
Revoked from now, for good: the next request with it is 401. A key you did not make there is 404 not-found; one revoked already - by you, or by the account's own people - is answered as it stands. 403 cut-off for an account whose owner cut you off.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_idpath · stringrequiredkey_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.
Responses
200 Successful response
idstringrequiredprefixstringrequirednamestringrequiredenv"live" | "test"requiredagentstringrequiredcreated_atstringrequiredlast_used_atstring or nullrevoked_atstring or nullWhen it was revoked, for good - by you, or by the account's own people. Null while it works.
- 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/accounts/{account_id}/invitationScope accountsSend the owner's invitation again
Until the owner of an account you opened has joined it: the invitation waiting is withdrawn and another sent - to the same address, or a corrected one. Once they have joined it is 409, owner_joined: its people are theirs to invite, and you invite nobody. Refused as opening refuses an owner's address (422, format, in_your_account), and 503 sign-in-unavailable where Clerk could not be asked: nothing sent. A retry with the same Idempotency-Key gets the same answer, email null.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_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
emailstringrequiredThe address the owner signs in with. They are emailed an invitation to the account, and join it signed up at that address. Never a person of your own account, who cannot join another (
in_your_account).
Responses
200 Successful response
status"waiting" | "accepted" | "withdrawn" | "expired"requiredwaitingfor them to take it up;accepted, they joined - the account is theirs to run;expired, not taken up in time - send it again.invited_atstringrequiredexpires_atstringrequiredemailstring or nullThe address you sent it to, while it waits, to send it again from - or to another: in one account's read (
GET /v1/accounts/{account_id}), and null in the list. Null once they have joined: their address is theirs.emailed_atstring or nullWhen Himmel's email with the invitation's link went to them: who opened the account for whom, what waits for them, and the link, which you never see. Null until it has gone, and where their mail server refused the address - send it again, to one it takes - and where the deployment sends no email of its own, when Clerk sent its own.
joined_atstring or nullWhen they joined. Null until they have.
- 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/accounts/{account_id}/policiesScope accountsPost a playbook from a template in an account you opened
A template filled with your figures for the customer, as POST /v1/policies fills one: its document, rules and worked examples saying them, in the account's currency, posted as a draft its owner confirms rule by rule - a new playbook's 1.0.0, or the next version of the one it has; a draft of it already there is 409, naming it, and is filled again with PUT. Never its files, and never switched on: its owner does that. 404 not-found for an account yours did not open, 403 cut-off for one whose owner cut you off.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_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
templatestringrequiredOne of our templates, by its name (
GET /v1/templates).valuesobjectrequiredEvery blank of the template and your figure for it, by the blank's name: money as an integer
amountin minor units with the 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, and its owner confirms each rule with its figure, or changes it.
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/accounts/{account_id}/policies/{policy_id}Scope accountsFill a draft playbook again in an account you opened
A draft of the playbook filled from a template, filled again with your figures: the rules a changed figure reaches wait for its owner again, and the rest keep their confirmations. Only a draft filled from that template - one the account's own people posted as files is 409, not_from_a_template, and a version switched on never changes. 404 not-found for an account yours did not open or a version it does not have, 403 cut-off for one whose owner cut you off.
Needs a person signed in whose role carries accounts: no key can hold it. 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
account_idpath · stringrequiredpolicy_idpath · stringrequired
Request body · application/json
templatestringrequiredOne of our templates, by its name (
GET /v1/templates).valuesobjectrequiredEvery blank of the template and your figure for it, by the blank's name: money as an integer
amountin minor units with the 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, and its owner confirms each rule with its figure, or changes it.
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.