View Markdown

Asks and answers

An ask is a message with an ask field: the agent stops and waits for a person’s decision. ask.type says how the question is shown; the answer’s resolution.decision says what it means.

Kinds of ask

ask.type You see The answer
confirm Approve and Reject, or up to 4 buttons of your own, each meaning approve or reject decision: approve or reject
choice 2 to 12 options; multiple: true lets you pick several, allow_other lets you type your own decision: respond, with option or options
multi 2 to 12 options to tick, between min and max of them decision: respond, with options
text A text field, with optional suggestions decision: respond, with text
form Up to 10 fields: text, numbers, yes or no, one or several of a list, a date decision: respond, with values

A two-button confirm is answered right from the notification, on the Lock Screen; anything richer opens Kabu. Any ask can let you decline instead (decision: reject), and allow_comment adds a note to the answer.

{
  "title": "Run the production migration?",
  "body": "Adds `orders.archived_at`. About a 3 s lock.",
  "action": { "name": "db.migrate", "args": { "version": 42, "env": "prod" } },
  "ask": { "type": "confirm", "irreversible": true }
}

action says what will run if you approve, and Kabu shows it with the question. With allow_edit, you may change its arguments: the decision is then edit, with the arguments you approved in edited_args.

Decisions

Branch on resolution.decision, never on the button’s label:

decision Means
approve Do exactly what was asked
reject Do not, or the person declined to answer; comment may say why
edit Do it, with edited_args instead of the proposed arguments
respond The answer is the value: option, options, text or values
ignore Skip this step: only when an option offered it

A decision you do not recognise is never approval. The resolution also records who answered (responded_by), where (via: the Lock Screen, the app, the web) and how sure Kabu is it was them (assurance), and carries a signed receipt.

Waiting, and expiry

An ask waits until it is answered, cancelled or expires (expires_in, an hour unless you say; from a minute to 30 days). Wait for it with ?wait= on POST /v2/messages and GET /v2/messages/{message_id}, or with kabu ask, which waits as long as it takes.

Expiry never approves anything. Unanswered, an ask ends expired with no decision, unless it set ask.on_expire to a safe default (reject, respond with a value, or ignore), which Kabu then applies and marks as the system’s. An agent cannot schedule its own approval.

Irreversible asks

irreversible: true is for the steps you cannot take back: approving needs your phone unlocked, and the ask is never settled by its expiry (on_expire is refused). Use it for production deploys, migrations and deletions.

Who may answer

The people it was sent to (to), from the Kabu app and its notifications, or the link Kabu sends them. With several recipients, the first answer settles the ask and the others’ notifications are withdrawn. A service of yours can answer on a person’s behalf with a key holding answers:delegate.

The key that asked never can: any key that may send messages is refused with 403 self_response_forbidden, so an agent cannot approve its own request. An answer to a settled ask is 409 already_settled; one after the deadline, 410 ask_expired.