create_confirmation
Sends an encrypted human-in-the-loop approval request to configured channels, with the first response deciding the outcome.
Instructions
Create a HITL confirmation request. Sends an approval request to the channels configured on the referenced HITL config. First response wins.
Agent usage: The HITL config referenced by hitl_id must be authorized before you can create confirmations. If this returns a 403 or "not authorized" error, call request_hitl_authorization on the HITL config first, then wait for the user to approve via the messaging channel. After creating a confirmation, poll get_confirmation to check for approval/denial, or, if the user (the HITL config owner) will decide it themselves, use get_confirmation_approval_link for their own approval link.
Encryption is NOT optional: a HITL config cannot send confirmations without a keypair, the human approves by decrypting in their browser, and message must be a JSON ciphertext envelope. Plaintext is refused with 400 message_not_encrypted; an envelope sealed to another key with 400 message_key_mismatch. Choose the version by who must be able to decrypt:
v1 (single-recipient): wraps the content key for the config owner only. Use ONLY when there are no enrolled non-owner approvers — with approvers enrolled it is refused with 400
envelope_missing_approvers.v2 (multi-recipient): additionally wraps the content key for each enrolled approver via an
approver_ekmap, so every approver can decrypt. Build it with the SDKencryptMessageV2(plaintext, ownerPublicKey, hitlId, approverKeys)after fetching the approvers via the SDKgetApproverKeys(hitlId)(GET /api/v1/hitl/:id/approver-keys). AAD is thehitlId.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hitl_id | Yes | HITL config ID whose channels will receive the approval request | |
| message | Yes | The client-encrypted ciphertext envelope as a JSON string (v1 or v2) — NOT the human-readable text. Encrypt the sentence the approver should read; passing it directly is refused with 400 `message_not_encrypted`, because the approval page can only decrypt an envelope. | |
| proof_expiry_days | No | Per-request proof expiry override in days (7, 30, 90, or 365) |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | MongoDB ObjectId | |
| status | No | Status of a confirmation request. A confirmation that times out is `denied`, with `response.channel` `system` and `response.text` `timeout`. | |
| hitl_id | No | ||
| message | No | The stored ciphertext envelope, echoed back verbatim. The server never sees the plaintext, so this is never the human sentence — the approver decrypts it in their browser. | |
| resends | No | Every "Send again" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it. | |
| response | No | The decision and its evidence (null while pending) | |
| created_at | No | ||
| timeout_at | No | When this confirmation will time out | |
| updated_at | No | ||
| proof_token | No | Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`) | |
| resolved_at | No |