Consent UX (Human-in-the-Loop)
The Consent UX system provides human-in-the-loop approval workflows for AI agent actions. When an agent attempts an action that requires explicit human authorization — based on risk level, action type, or custom policies — Mandaitor creates a consent request that must be resolved by an authorized approver before the action can proceed.
When Consent Is Required
Consent requests are triggered automatically based on consent policies configured by the tenant. Policies define which actions, risk levels, or conditions require human approval before execution.
| Trigger | Example |
|---|---|
| Risk level | All HIGH or CRITICAL risk actions require approval |
| Action pattern | Any action matching finance.transfer.* above €10,000 |
| First-time action | Agent performing an action type for the first time |
| Drift threshold | Agent's drift score exceeds the configured threshold |
Consent Flow
The consent flow integrates with the standard verification pipeline:
Creating Consent Policies
Consent policies define the rules for when human approval is required:
await client.post("/consent-policies", {
name: "High-Value Transactions",
description: "Require approval for financial actions above threshold",
conditions: {
action_patterns: ["finance.transfer.*", "finance.approve.*"],
risk_levels: ["HIGH", "CRITICAL"],
constraint_match: {
"amount_eur": { "gt": 10000 },
},
},
approvers: [
{ type: "role", value: "finance-manager" },
{ type: "subject", value: "user:cfo@company.com" },
],
timeout_hours: 24,
escalation: {
after_hours: 4,
to: "user:ceo@company.com",
},
});
Managing Consent Policies
Consent policies can be listed, inspected, updated, and deleted through the tenant API. This is useful when approval routing must evolve without changing mandate records.
| Operation | Endpoint | Purpose |
|---|---|---|
| List policies | GET /consent-policies | Returns all tenant-level approval policies. |
| Get policy | GET /consent-policies/{id} | Retrieves one policy including conditions, approvers, timeout, and escalation metadata. |
| Update policy | PUT /consent-policies/{id} | Replaces the policy definition. Existing consent requests keep their historical policy snapshot. |
| Delete policy | DELETE /consent-policies/{id} | Removes the policy from future verification decisions. |
await client.put(`/consent-policies/${policyId}`, {
name: "High-Value Transactions",
conditions: {
action_patterns: ["finance.transfer.*"],
risk_levels: ["HIGH", "CRITICAL"],
},
approvers: [{ type: "role", value: "finance-manager" }],
timeout_hours: 12,
});
Listing Pending Consents
Approvers can view their pending consent requests:
GET /consents/pending
This returns all consent requests awaiting the caller's decision, ordered by creation time.
Resolving a Consent Request
Approvers resolve consent requests through the implemented POST /consents/{id}/resolve endpoint. Resolution records the decision, reviewer context, reason, and optional conditions into the audit trail before the agent retries verification:
await client.post(`/consents/${consentId}/resolve`, {
decision: "APPROVED",
reason: "Reviewed and confirmed within project budget",
conditions: {
valid_until: "2026-06-01T00:00:00Z",
},
});
Rejection permanently blocks the specific action attempt. The agent must create a new verification request if it wishes to retry. Applications can retrieve the current request state through GET /consents/{id} before rendering an approval screen, which prevents stale or already-resolved requests from being approved twice.
Viewing Consent History
All consent requests for a specific mandate can be retrieved:
GET /mandates/{id}/consents
This provides a complete audit trail of all human-in-the-loop decisions made for a given mandate.
The Consent UX system is currently Stable. The policy engine and approval flows are production-ready. Escalation timing and notification channels may evolve based on feedback.