Skip to main content

Approvals inbox

The Approvals inbox screen lets you read the requests that wait for a human decision (tool calls, run steps, promotions, break glass) and approve, reject or cancel them. Portal path: /agents/approvals. Approvers (tenant administrators, security officers, developers, business owners) decide the requests; the requester can only cancel them. The screen is drawn by portal/src/screens/agents.tsx.

What the screen shows​

  • Approval requests table, read with GET /v1/approvals (50 rows per call, cursor paging). Before it answers, the Control Plane marks the requests whose deadline passed as expired. Columns: Id, Action, Resource type, Resource id, Requester, Reason, Status, Created.
  • Filter Status (Pending, Approved, Rejected, Cancelled, expired, or all), then Filter.
  • When the list is empty: Nothing waiting for approval, with the hint Requests appear here when a policy requires a human decision. Requests are created by the platform (a policy obligation, a tool marked requires_approval, a promotion to active or approved); this screen has no create button.
  • A click on a row, or the row menu View details, opens a side panel with the request read with GET /v1/approvals/{approval_id}: its timeline when it has one, then the full JSON (payload, quorum, approver roles, decisions).

Actions​

The row actions show only while the request is pending.

Button or actionWhat it doesAPI callRoles
Refresh (icon)Reloads the list.GET /v1/approvalsAny tenant member
FilterApplies the Status filter.GET /v1/approvals with statusAny tenant member
Row click or row menu View detailsOpens the detail panel.GET /v1/approvals/{approval_id}Any tenant member
Row menu ApproveOpens a form with an optional Comment, then records an approval. The request becomes approved when the number of approvals reaches its quorum.POST /v1/approvals/{approval_id}/decideRoles of approver_roles, by default tenant_admin, security_officer, developer, business_owner; never the requester
Row menu RejectOpens a form with a required Comment, then rejects the request at once.POST /v1/approvals/{approval_id}/decideSame as Approve
Row menu CancelOpens a form with a required Reason (3 to 2000 characters), then withdraws the request.POST /v1/approvals/{approval_id}/cancelThe requester, tenant_admin, security_officer
Retry (error state)Sends the failed read again.Same callSame roles

The decision forms send this body (decision is approve or reject):

{"decision": "reject", "comment": "Amount above the delegation of the requester"}

Roles​

The portal hides no action; the rules live in services/control-plane/src/eai/domains/approvals/service.py:

  • Separation of duties: the requester, and every user listed in payload.excluded_approvers, cannot decide the request (separation_of_duties, 403).
  • Approver roles: the request may set its own approver_roles; otherwise DEFAULT_APPROVER_ROLES applies (tenant_admin, security_officer, developer, business_owner). platform_admin passes every role check.
  • One decision per person: a second decision by the same approver is refused (already_decided).
  • Quorum: one rejection closes the request; approvals are counted until the quorum (1 to 10) is reached.
  • Cancel: the requester, or a member of CANCELLERS (tenant_admin, security_officer).

Every decision and cancellation is written to the audit log.

Typical tasks​

Approve a pending request​

  1. List what waits. Only pending requests can be decided. Choose Pending in Status and click Filter. Expected result: the pending requests, newest first. If it fails: Nothing waiting for approval means nothing is pending for the tenant.
  2. Read the request. The payload tells what will run if you approve. Click the row and read action, resource_type, payload and quorum in the panel. Expected result: you know the action and its impact. If it fails: when the panel shows an error, click Retry.
  3. Approve it. Your approval is counted toward the quorum. In the row menu, click Approve, add a Comment, then click Approve. Expected result: the toast Done; the status becomes Approved, or stays Pending while the quorum is not reached. If it fails: separation_of_duties means you are the requester; ask another approver.

Reject a request with a reason​

  1. Open the form. A rejection must be explained to the requester and to the auditors. In the row menu, click Reject. Expected result: a form with Comment. If it fails: the action is missing when the request is no longer pending.
  2. Write the comment and confirm. The comment is stored with the decision. Type the reason and click Reject. Expected result: the toast Done and the status Rejected; a waiting run receives the rejection. If it fails: Required under the field means the comment is empty.

Withdraw your own request​

  1. Cancel it. A request that is no longer needed must not stay in the inbox of the approvers. In the row menu, click Cancel, type a Reason of at least 3 characters, then click Cancel. Expected result: the toast Done and the status Cancelled. If it fails: forbidden (403) means you are neither the requester nor tenant_admin nor security_officer.

Troubleshooting​

SymptomCauseFix
separation_of_duties (403): "Separation of duties: the requester cannot approve their own request."You created the request, or you are listed in excluded_approvers.Another approver must decide.
forbidden (403) with required_rolesYour roles are not in the approver roles of the request.Ask an approver who holds one of the listed roles.
already_decided (409): "You already decided on this approval."You already recorded a decision on this request.Wait for the other approvers to reach the quorum.
approval_closed (409): "The approval is already ..."The request was decided, cancelled or expired meanwhile.Click Refresh; a new request is needed to retry the action.
Status stays Pending after ApproveThe quorum asks for more approvals.Read quorum in the detail panel and ask other approvers.
validation_error (422) on CancelThe reason is shorter than 3 characters.Write a longer reason.