Skip to content
Wetel
Go back

Designing approval steps people actually read

Two expense claims land on a manager’s desk on the same afternoon.

The first says: “Expense claim. Please approve.” To decide, the manager has to open the receipt, find the policy, work out which client it was for and check the amount against the limit. They are busy. They click approve.

The second says: “Taxi, RM 48, client visit to the Shah Alam office on 3 November. Within the RM 60 limit. Receipt attached.” The manager reads it in five seconds and decides properly, either way.

Both requests asked for the same thing. Only one of them made a real decision possible. An approval step in an AI employee’s workflow works exactly the same way: the step is only as good as the request it puts in front of a person.

We have already written about which actions should wait for a person at all and what happens when nobody answers in time. This post is about the request itself: how to design it so the manager decides quickly and well, instead of clicking through.

First, an approval is a step you add

In Wetel, an approval is a node you place in a workflow. It is not switched on for you: if you do not add the step, the AI employee does not stop to ask. So the choices below are yours, made for the actions that matter.

When the run reaches the step, it parks, a request opens, and a workspace owner approves or rejects it. The run then continues down one of three labelled paths: approved, rejected or expired.

flowchart LR
T["response: I've asked a manager"] --> P{{approval}}
P -- approved --> A["do the action, then confirm"]
P -- rejected --> R["explain, include the comment"]
P -- expired --> E["someone will follow up"]

Write a title that is the decision

The title is what the approver sees first, in the approvals inbox and in the in-app notification. The field is titleTemplate, a template filled in from the run’s context, so it can carry the real values of this case. It is cut at 200 characters.

“Refund request” tells the owner only that work is waiting. “Refund of 40 for order 8841” tells them what they are deciding before they open anything. With several requests waiting, that is the difference between a list someone can triage and one they work through blindly.

A useful test: if the owner only ever read titles, could they at least tell which requests are urgent or unusual?

Write a summary that makes opening anything else unnecessary

The summaryTemplate is the longer text the approver reads (up to 4,000 characters, also filled in from context). The aim is the second expense claim: everything needed to decide, in the request itself.

Here is a weak version, close to what most first drafts look like:

{
"titleTemplate": "Refund request",
"summaryTemplate": "The customer wrote: {{userMessage}}",
"saveAs": "approval"
}

It passes the customer’s last message along and leaves the owner to work out the rest: which order, how much, why, and what approving will actually do.

And a stronger one. Here refund is a context variable an earlier step in your workflow filled in (for example an action node with outputVar: "refund"); the field names inside it are yours:

{
"titleTemplate": "Refund of {{refund.amount}} for order {{refund.orderId}}",
"summaryTemplate": "Customer asked for a refund of {{refund.amount}} on order {{refund.orderId}}.\nReason they gave: {{refund.reason}}\n{{#if refund.note}}Note from the AI employee: {{refund.note}}\n{{/if}}If you approve, the refund is issued in the next step and the customer is told. You can change the amount before approving. If you reject, the customer is told it was declined, with your comment.",
"payloadVar": "refund",
"editableFields": ["amount"],
"saveAs": "approval",
"expiresAfterSeconds": 86400
}

Three things make the second one work:

  1. The facts the decision rests on, filled in from context rather than paraphrased by a model. A number shown to an approver should come from the step that produced it.
  2. The consequence of each button. “If you approve, X happens; if you reject, the customer hears Y.” People decide better when they can see what their click does.
  3. What they can change. If the approver may correct a value, say so in the summary, so they know editing is an option and not only yes or no.

Keep it short enough to read. 4,000 characters is a limit, not a target.

Put the thing being decided in the request, and allow edits only to named fields

The payloadVar field names a context variable holding the object under decision, such as an order or a draft refund. The approver sees it alongside the summary. It is limited to 64 KB, and secret-shaped values in it are redacted.

editableFields lists the keys of that payload the approver may change while approving. Any edit to another key is refused. This is a design decision, not a formality: decide which values a manager may reasonably correct (an amount, a date, a line of wording) and which must stay as they are (an order id, a customer id). If only the amount should change, list only amount.

Two behaviours to plan around:

Choose an expiry that matches the work

Every request has a deadline: expiresAfterSeconds, 72 hours by default, from 1 second up to 14 days. Pick it from the work, not from the default:

A deadline that is too long leaves the customer in limbo. One that is too short trains everyone to expect expiries and stop looking. Once it passes, the request cannot be decided at all, even a moment later.

Write all three replies as a person would want to receive them

The approval node says nothing to the end user. Everything the customer hears comes from the steps you put around it, so write each one deliberately:

One detail: when the approver leaves no comment, {{approval.comment}} renders as blank. Write the reply so it still reads well without it. “Sorry, we couldn’t approve this one.” should be a complete sentence on its own.

It also helps to ask approvers to add a short comment when they reject. It costs them a few seconds, and it is the only explanation the customer will get.

One request per consequential action

It is tempting to bundle: one request for “these five refunds”, decided once. A decision applies to the whole request, though. The owner approves or rejects it as a unit, so a bundle forces an all-or-nothing call, and the one questionable item hides among four routine ones.

Our default advice: one request per action that has its own consequence, with its own title and payload. Bundle only items that are genuinely the same decision. A run can hold at most 5 pending approvals at once, which is a useful reminder that a workflow asking for approval again and again probably needs redesigning, not more requests.

Know what the approver sees, and who the approver is

When a request opens, every active workspace owner gets an in-app notification titled “Approval needed”, and the request appears in the approvals inbox with its title, summary, payload, the editable fields, status and deadline. Owners can approve, reject with a comment, edit the allowed fields while approving, or cancel a request (which leaves the run paused for good).

Today’s limits, so you can design around them:

Every request competes for the attention of a few owners, one more reason to make each one quick to read.

Test every outcome before anyone sees it

In a draft test you can simulate the decision with draftApprovalOutcome: APPROVED, REJECTED or EXPIRED. The approval node completes at once, no request is created, nobody is notified, and the run follows only that path. Run all three and read each reply as the customer would.

One caution: plan as if the steps after a simulated approval run for real. If your approved path calls a business system, test it against something safe. More on drafts in how to try a workflow safely before customers see it.

Watch for approval fatigue in the records

Approval fatigue is when people approve without reading. It does not announce itself; you find it by looking.

Every decision is kept. The decision saved under saveAs records who decided, any comment, and the payload after edits, and it sits in the run’s context, which you can read in the run record. The inbox can also list requests by status, not only pending ones.

Every few weeks, look through them with a few questions in mind:

There are no figures to hit. It is the habit of a manager reading a sample of past expense claims: checking that the control still means something.

To build your first well-designed approval step, follow Human approval: a walkthrough.


Share this post:

Next Post
Procedures you can read: why an AI employee should follow a graph, not one long prompt
Previous Post
How do people reach an AI employee?