Skip to main content

What we’re building

We will build a refund workflow. A refund of 50 or less is approved by a rule. A larger one stops and asks a person. The run waits, as long as we allow, and then continues down the branch the answer picks. A step like ask raises an input request: a typed question with a prompt, the answers on offer, and a risk. The risk decides who may answer. Risk HIGH can only be answered by a person, never by a supervisor or an AI agent. Money is a good reason for that.
1

Save the workflow

Create refund.json:
refund.json
The ask node waits for up to ttlSeconds (600, ten minutes). onTimeout: FAIL fails the step if nobody answers in time, so a refund is never paid by silence. After an answer, the message carries the decision in its metadata as input.decision, and verdict branches on it. Send it to the server:
You should see:
With an API key on the server, add -H "X-API-Key: <your key>" to every call in this tutorial.
Stuck? ASK_INPUT as an unknown type means the server is older than this feature or was built without it. curl http://localhost:9858/api/plugins/ASK_INPUT answers 404 in that case.
2

Send a small refund: a rule decides

Take the executionId from the answer and read the result:
You should see a refund approved by the rule, and nobody was asked:
3

Send a big refund: the run waits

Set EXEC to the new executionId, and read the run:
You should see the run still RUNNING, with ask running and everything after it pending:
Stuck? If ask is SKIPPED and the run already finished, the amount was 50 or less and the rule took it. Use an amount above 50.
4

Find the question

The question is now open. List the open questions of the session:
You should see the request (shortened). Note risk and options:
Keep its id:
In the web UI the same question shows in the Inputs panel of the workflow page, with a button for each option.
5

Answer it

We approve, and give a reason. The reason is recorded in the execution log:
You should see the request ANSWERED, with who answered (shortened):
The run goes on at once. Read its result as in step 2:
Stuck? 409 means the request is no longer open: someone answered it, or it expired. The message names the answer that won. 403 names the rule that failed (audience, tier, risk, scope or separation). Answering needs an OPERATOR key, and a request of risk HIGH is refused to a supervisor whatever its settings.
6

Say no

Start another big refund the same way, with another order, and find its question:
Set EXEC and REQ for it as in step 4, then reject:
You should see the run finish SUCCESS with the other branch taken:
A rejection is only a decision here, so verdict sends it to declined and the run records the outcome. Answering the same question again is refused:
With the command-line client:
An assistant uses the MCP tools list_pending_inputs and answer_input. The yukta-workflows skill tells it to show you what waits and let you choose: approving is your decision, not the assistant’s.
Without an API key every caller counts as a person, so this tutorial worked with no header. Once the server has keys, answering needs an OPERATOR key, and the answer is recorded under that key’s name.

What you just did

We made a workflow that handles the routine cases by rule and stops at the one that needs a person. The ask step turned into a typed question that we listed, read and answered over REST, and the run carried on with our answer. Whoever answers is checked against the request’s risk, so a high-risk question cannot be answered by anything but a person.

Where to go next

Who decides

Risk tiers, routes and why HIGH is a human decision.

Ask for input from a workflow

ASK_INPUT, the ask_for_input tool for agents, and WAIT_FOR_SIGNAL.

Route input requests

Send questions to a supervisor first, then to a person.

Add a supervisor

Let a rule answer or advise on the low-risk questions.