Veefore docs

Approvals queue

Give it an owner, measure the response time, and understand why an expired approval is worse than a denied one.

The queue is the thing most likely to rot

ENFORCE with approval rules and an unwatched queue is just a slower kind of blocked. Approvals reaching APPROVAL_EXPIRED are actions that silently did not happen, and nobody gets an alert about silence.

Before you promote to ENFORCE, decide: who owns it, what the response-time expectation is, and what happens out of hours.

#Work it

/approvals in the console, with a pending-count badge.

Each card carries the full decision context, which is deliberate:

  • The agent, its delegation chain, and what it is acting for
  • The tool, the capability, the parameters, the amount
  • The policy and rule that required approval, with the conditions that matched
  • The risk level, score and every signal that fired, each with its explanation
  • The agent's recent action history
  • The purpose the agent supplied
  • The blast radius, for a destructive tool

An approver without context approves everything

Which is worse than having no approval step, because now there is a record saying a human reviewed it.

If approvers are routinely approving without reading, the problem is one of two things: the cards do not carry enough context, or the rule fires too often to be meaningful. Both are fixable. Neither is fixed by asking people to read more carefully.

#Deny with a real reason

bash
curl -X POST $CP/v1/approvals/apr_01ABC/deny \
  -H "Authorization: Bearer $KEY" \
  -H 'content-type: application/json' \
  -d '{ "reason": "Order ord_8812 was already refunded on 1 Oct" }'

The reason reaches the agent as the message on APPROVAL_DENIED, so it can report something meaningful upstream instead of "the request failed". "Denied" on its own wastes the one chance to explain.

#Measure it

promql
histogram_quantile(0.95,
  rate(veefore_approval_decision_duration_seconds_bucket[1h]))

Your approval SLA, measured rather than asserted.

If p95 exceeds your rule TTLs, your approvals are expiring systematically

Default TTL is 900 seconds. A p95 of 1,400 seconds means a large share of approvals never get decided — and each one is an action that did not happen with nothing to indicate it.

Fix one of: the TTL, the staffing, or the rule that fires too often.

Alert on it:

yaml
- alert: VeeforeApprovalsNotBeingWorked
  expr: |
    histogram_quantile(0.95,
      rate(veefore_approval_decision_duration_seconds_bucket[1h])) > 900
  for: 30m
  labels: { severity: warning }

#Route it somewhere people are

Subscribe a webhook to approval.requested and push it into chat.

bash
curl -X POST $CP/v1/webhooks \
  -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
  -d '{
    "name": "approvals-to-chat",
    "url": "https://hooks.internal.example.com/veefore-approvals",
    "event_types": ["approval.requested"]
  }'

Verify the signature, then read state from the API

A webhook is a notification, not an authorization. Approving must happen through the console or the API by an authenticated person holding approval:approve.

Do not build a chat bot that approves on a reaction without re-authenticating. That turns chat membership into approval authority.

#Set the TTL per rule

json
{
  "then": {
    "decision": "REQUIRE_APPROVAL",
    "reason": "Refunds above ₹1,000 require a human approver.",
    "approval": {
      "routingMode": "SINGLE",
      "requiredApprovals": 1,
      "approverRoleKeys": ["APPROVER"],
      "ttlSeconds": 900
    }
  }
}

Match the TTL to how fast a human can realistically respond to that particular thing, not to a round number.

Situation TTL
Business-hours refund review 900–3600
Overnight batch needing morning sign-off 43200
Production deployment during a change window 1800
Anything a customer is waiting on as short as your staffing supports

An approval that always expires is a rule that always blocks, dressed up as a rule that asks.

#Routing

Mode Use when
SINGLE One named person decides. The default
GROUP Anyone on duty may decide. Best for an on-call rota
QUORUM Two or more must agree. For irreversible or large-blast-radius actions
SEQUENTIAL Ordered sign-off. For a genuine escalation chain

requireStepUp: true forces the approver to re-authenticate at the moment of approving. Use it for anything irreversible — it means an unattended, still-valid browser session is not enough.

When several rules both require approval, the effects merge conservatively: the maximum requiredApprovals, the minimum ttlSeconds, the union of approver roles, and requireStepUp true if any rule asked for it.

#Separation of duties

By default SECURITY_ADMIN does not hold approval:approve, and neither does DEVELOPER. Only APPROVER, ADMIN and OWNER do.

That is deliberate: the person who wrote the rule requiring approval should not be the person satisfying it. Grant the overlap explicitly if your organization genuinely wants it, having decided to.

#Tuning the rules themselves

Review monthly. For each approval rule ask:

Is it firing too often? A rule that fires on most actions is not a control, it is a tax, and approvers will start rubber-stamping. Narrow the condition or raise the threshold.

Is it never firing? Either the threshold is wrong or the rule is describing something that does not happen. Both are worth knowing.

Is it being worked around? If a human is regularly doing the thing manually after an approval is denied, the rule is wrong, not the control. Find out what it should have said.

Is the right person deciding? An approver who always defers to someone else is not the approver; the person they ask is. Change the routing.

Identity, authority, policy and enforcement for autonomous AI agents.