Approval Workflows

Not every governance decision should be automated. Some actions — privilege escalation, bulk data operations, financial transactions — require a human to review and approve before they proceed. MITRITY's approval workflow system lets you define hold policies that pause agent actions and route them to a human approval queue.

This guide covers the end-to-end approval workflow: defining hold policies, managing the approval queue, configuring timeouts, and setting up notifications.

How Hold Policies Work

When the gateway evaluates an agent action and the matching policy has policy_type: "hold", the following sequence occurs:

  1. Action paused — The gateway holds the agent's request in memory and returns a 202 Accepted response with a pending approval ID.
  2. Approval created — The control plane creates an approval record with status pending and starts the timeout clock.
  3. Notifications sent — If configured, MITRITY sends notifications to the designated channels (email, Slack, webhook).
  4. Human reviews — An authorized user reviews the pending action in the dashboard or via API.
  5. Decision applied — The user approves or denies the action. The gateway receives the decision and either forwards the original request or returns an error to the agent.
  6. Timeout fallback — If no human responds before the timeout expires, the timeout_action determines the outcome (auto-deny or auto-allow).
Agent ──action──► Gateway ──hold──► Control Plane ──notify──► Slack / Email
                     │                     │
                     │◄────decision─────────┤◄────approve/deny──── Human
                     │                     │
                     ▼                     ▼
              forward or block       log audit event

Defining a Hold Policy

Hold policies use the same structure as other policies, with additional fields for timeout configuration.

Policy Structure

{
  "name": "hold-iam-changes",
  "description": "Require human approval for IAM privilege changes",
  "policy_type": "hold",
  "action_pattern": "regex:^iam\\.(create_role|assign_role|escalate_permissions)$",
  "priority": 400,
  "enabled": true,
  "hold_timeout_minutes": 15,
  "timeout_action": "deny",
  "constraints": {
    "agent_id": ["agent-infra-bot", "agent-devops-bot"]
  }
}

Hold-Specific Fields

FieldTypeRequiredDescription
hold_timeout_minutesintegerYesMinutes to wait for a human decision before applying the timeout action. Minimum: 1, Maximum: 1440 (24 hours).
timeout_actionenumYesWhat happens when the timeout expires: "deny" (block the action) or "allow" (permit the action).

Creating a Hold Policy via API

curl -X POST https://api.mitrity.com/api/v1/policies \
  -H "Authorization: Bearer mk_live_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "hold-financial-transactions",
    "description": "Hold all financial transactions above $1000 for manual approval",
    "policy_type": "hold",
    "action_pattern": "finance.transfer_*",
    "priority": 350,
    "hold_timeout_minutes": 30,
    "timeout_action": "deny",
    "constraints": {
      "resource_pattern": "amount:>1000"
    }
  }'

Response:

{
  "data": {
    "id": "pol_8f3k2m1n",
    "name": "hold-financial-transactions",
    "description": "Hold all financial transactions above $1000 for manual approval",
    "policy_type": "hold",
    "action_pattern": "finance.transfer_*",
    "priority": 350,
    "hold_timeout_minutes": 30,
    "timeout_action": "deny",
    "enabled": true,
    "constraints": {
      "resource_pattern": "amount:>1000"
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-01T10:00:00Z"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-01T10:00:00Z"
  }
}

Common Hold Policy Examples

Privilege Escalation

Hold any action that modifies IAM roles or grants elevated permissions:

{
  "name": "hold-privilege-escalation",
  "policy_type": "hold",
  "action_pattern": "regex:^(iam|rbac)\\.(create_role|assign_role|grant_permission|escalate)$",
  "priority": 500,
  "hold_timeout_minutes": 15,
  "timeout_action": "deny"
}

Bulk Data Operations

Hold bulk export, delete, or migration operations:

{
  "name": "hold-bulk-operations",
  "policy_type": "hold",
  "action_pattern": "regex:^bulk_(export|delete|migrate)_.*$",
  "priority": 450,
  "hold_timeout_minutes": 60,
  "timeout_action": "deny"
}

Infrastructure Changes

Hold infrastructure modifications during business hours:

{
  "name": "hold-infra-changes",
  "policy_type": "hold",
  "action_pattern": "infra.*",
  "priority": 400,
  "hold_timeout_minutes": 30,
  "timeout_action": "deny",
  "constraints": {
    "time": {
      "after": "08:00",
      "before": "18:00",
      "timezone": "Europe/Stockholm"
    }
  }
}

Database Schema Changes

Hold any DDL operation with a long timeout for DBA review:

{
  "name": "hold-schema-changes",
  "policy_type": "hold",
  "action_pattern": "regex:^db\\.(alter_table|create_table|drop_table|create_index|drop_index)$",
  "priority": 480,
  "hold_timeout_minutes": 1440,
  "timeout_action": "deny"
}

The Approval Queue

Dashboard View

The approval queue is accessible from the MITRITY dashboard at Governance > Approvals. The queue displays:

  • Pending approvals sorted by creation time (oldest first)
  • Agent name and ID that triggered the action
  • Action type and parameters
  • Policy name that matched
  • Time remaining before timeout

Each pending approval shows the full context of the agent's action, including:

  • The raw action payload
  • The agent's declared mission scope
  • Historical behavior patterns for this agent
  • The current drift score
  • Related recent audit events

Filtering the Queue

Filter pending approvals by:

FilterDescriptionExample
AgentShow approvals for a specific agentagent_id=agent-sales-bot
PolicyShow approvals triggered by a specific policypolicy_id=pol_8f3k2m1n
Action typeFilter by action patternaction_type=iam.*
Time rangeShow approvals created within a rangecreated_after=2026-03-01T00:00:00Z
EnvironmentScope to a specific environmentenvironment_id=env_production

Approve or Deny via Dashboard

To review a pending approval in the dashboard:

  1. Navigate to Governance > Approvals.
  2. Click on a pending approval to see the full context.
  3. Review the action details, agent mission scope, and drift score.
  4. Click Approve or Deny.
  5. Optionally add a reason (recommended for audit trail).
  6. The decision is applied immediately.

After a decision:

  • Approved: The gateway forwards the original agent request. The audit event is logged with decision: "allow" and approval_status: "approved".
  • Denied: The gateway returns an error to the agent. The audit event is logged with decision: "deny" and approval_status: "denied".

Approve or Deny via API

List Pending Approvals

Retrieve all pending approvals for your tenant:

curl https://api.mitrity.com/api/v1/approvals?status=pending \
  -H "Authorization: Bearer mk_live_your-api-key"

Response:

{
  "data": [
    {
      "id": "apr_9x2k4m",
      "status": "pending",
      "agent_id": "agt_sales-bot",
      "agent_name": "sales-bot",
      "action_type": "bulk_export_contacts",
      "action_params": {
        "format": "csv",
        "filters": { "region": "EMEA" },
        "estimated_rows": 15420
      },
      "policy_id": "pol_8f3k2m1n",
      "policy_name": "hold-bulk-operations",
      "environment_id": "env_production",
      "timeout_at": "2026-03-01T11:00:00Z",
      "timeout_action": "deny",
      "created_at": "2026-03-01T10:00:00Z"
    }
  ],
  "meta": {
    "request_id": "req_def456",
    "timestamp": "2026-03-01T10:05:00Z",
    "next_cursor": null,
    "total": 1
  }
}

Approve an Action

curl -X POST https://api.mitrity.com/api/v1/approvals/apr_9x2k4m/approve \
  -H "Authorization: Bearer mk_live_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Approved: EMEA contact export requested by sales director for quarterly review"
  }'

Response:

{
  "data": {
    "id": "apr_9x2k4m",
    "status": "approved",
    "decided_by": "user_jsmith",
    "reason": "Approved: EMEA contact export requested by sales director for quarterly review",
    "decided_at": "2026-03-01T10:06:00Z"
  },
  "meta": {
    "request_id": "req_ghi789",
    "timestamp": "2026-03-01T10:06:00Z"
  }
}

Deny an Action

curl -X POST https://api.mitrity.com/api/v1/approvals/apr_9x2k4m/deny \
  -H "Authorization: Bearer mk_live_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Denied: No business justification provided for bulk export of 15K contacts"
  }'

Response:

{
  "data": {
    "id": "apr_9x2k4m",
    "status": "denied",
    "decided_by": "user_jsmith",
    "reason": "Denied: No business justification provided for bulk export of 15K contacts",
    "decided_at": "2026-03-01T10:06:00Z"
  },
  "meta": {
    "request_id": "req_jkl012",
    "timestamp": "2026-03-01T10:06:00Z"
  }
}

Count Pending Approvals

Get a quick count of pending approvals (useful for badge counters):

curl https://api.mitrity.com/api/v1/approvals/count?status=pending \
  -H "Authorization: Bearer mk_live_your-api-key"

Response:

{
  "data": {
    "pending": 3,
    "approved_today": 12,
    "denied_today": 2,
    "timed_out_today": 1
  },
  "meta": {
    "request_id": "req_mno345",
    "timestamp": "2026-03-01T10:10:00Z"
  }
}

Timeout Behavior

When no human responds before the hold_timeout_minutes expires, the timeout_action determines the outcome.

Auto-Deny (Recommended)

{
  "timeout_action": "deny"
}

When the timeout expires, the action is blocked. The gateway returns an error to the agent. The audit event is logged with decision: "deny" and approval_status: "timed_out".

Use auto-deny when:

  • The action is high-risk (privilege escalation, data deletion, financial transactions)
  • It is better to err on the side of caution
  • The agent can retry the action later after explicit approval

Auto-Allow

{
  "timeout_action": "allow"
}

When the timeout expires, the action is permitted. The gateway forwards the original request. The audit event is logged with decision: "allow" and approval_status: "timed_out".

Use auto-allow when:

  • The action is low-to-medium risk and the hold is primarily for visibility
  • Blocking the agent on timeout would cause unacceptable downstream failures
  • You want human review when available, but default to permissive behavior

Timeout Recommendations

ScenarioRecommended TimeoutRecommended Action
Privilege escalation15 minutesdeny
Bulk data export60 minutesdeny
Infrastructure changes30 minutesdeny
Schema changes (DBA review)24 hours (1440 min)deny
Non-critical alerts30 minutesallow
After-hours monitoring60 minutesallow

Notification Channels

MITRITY can notify designated channels when a new approval is pending. Notifications include the full context of the action and a direct link to the approval in the dashboard.

Email Notifications (SendGrid)

Email notifications are sent via SendGrid to designated team members. Configure email recipients in the dashboard at Settings > Notifications > Approval Emails.

Each email includes:

  • Agent name and action type
  • Policy that triggered the hold
  • Action parameters (sanitized)
  • Time remaining before timeout
  • Direct link to approve or deny in the dashboard

Slack Notifications

Slack notifications are sent via incoming webhooks to designated channels. Configure the webhook URL in Settings > Notifications > Slack.

Example Slack notification:

:rotating_light: Approval Required
Agent: sales-bot
Action: bulk_export_contacts (15,420 rows)
Policy: hold-bulk-operations
Timeout: 60 minutes (auto-deny)
[View in Dashboard]

Webhook Notifications

For custom integrations, configure a webhook URL in Settings > Notifications > Webhooks. MITRITY sends a POST request with the approval details:

{
  "event": "approval.pending",
  "approval": {
    "id": "apr_9x2k4m",
    "agent_id": "agt_sales-bot",
    "action_type": "bulk_export_contacts",
    "policy_name": "hold-bulk-operations",
    "timeout_at": "2026-03-01T11:00:00Z",
    "timeout_action": "deny",
    "dashboard_url": "https://mitrity.com/app/approvals/apr_9x2k4m"
  },
  "timestamp": "2026-03-01T10:00:00Z"
}

Approval Permissions

Not every user can approve or deny actions. Approval permissions follow the MITRITY RBAC model:

RoleCan ApproveCan DenyCan View Queue
OwnerYesYesYes
ManagerYesYesYes
MemberNoNoYes
ViewerNoNoYes

Managers can only approve actions within their access scope. If a Manager's scope is limited to the "Development" environment, they can only approve actions from agents in that environment.

Audit Trail

Every approval decision is recorded in the audit log with full context:

{
  "id": "evt_abc123",
  "agent_id": "agt_sales-bot",
  "action_type": "bulk_export_contacts",
  "decision": "allow",
  "decision_source": "approval",
  "approval": {
    "id": "apr_9x2k4m",
    "status": "approved",
    "decided_by": "user_jsmith",
    "reason": "Approved: EMEA contact export for quarterly review",
    "wait_duration_seconds": 360,
    "policy_id": "pol_8f3k2m1n"
  },
  "timestamp": "2026-03-01T10:06:00Z"
}

The audit trail captures:

  • Who made the decision (user ID and email)
  • When the decision was made
  • The reason provided (if any)
  • How long the action waited in the queue
  • Whether the decision was manual or a timeout fallback

Best Practices

Start Narrow, Expand Gradually

Begin with hold policies on a small set of high-risk actions (IAM changes, bulk exports). As your team builds comfort with the approval workflow, expand to cover additional action types.

Set Reasonable Timeouts

Choose timeouts that balance security with operational needs. A 5-minute timeout on a database migration during off-hours will almost certainly auto-deny. Consider your team's response time when setting timeouts.

Always Provide Reasons

Encourage (or require) approvers to provide a reason with every decision. This creates a valuable audit trail and helps with post-incident analysis.

Use Environment Scoping

In multi-environment setups, consider different timeout and action configurations:

  • Production: Strict holds, short timeouts, auto-deny
  • Staging: Looser holds, longer timeouts, auto-allow
  • Development: Minimal holds, or monitor mode instead

Monitor Timeout Rates

If a large percentage of approvals are timing out, your timeouts may be too aggressive or the wrong people are being notified. Review the timeout rate in the dashboard at Governance > Approvals > Analytics.

Related Documentation

  • Writing Policies — Policy structure, pattern matching, and priority system
  • Enforcement Modes — How Monitor, Alert, and Enforce modes interact with hold policies
  • Policy Simulations — Test hold policies against historical data before deploying
  • RBAC — Role-based access control and approval permissions
  • API Overview — Full API reference for approval endpoints
Approval Workflows — Documentation | MITRITY