GuidesAI agents and human approval
n8n: approve a step from your phone
Human approval in an n8n workflow with an HTTP Request node: the question reaches your phone with buttons, and the workflow waits.
An n8n workflow runs on its own, often overnight. For some steps, you'd like it to stop and ask you. Here's how to do it with three nodes and an HTTP request.
What we want
Take a workflow that drafts replies to customer emails with a language model. The draft is fine nine times out of ten. The tenth time, you'd rather read it before it goes out. So we want:
- the workflow to send the draft to your phone, with two buttons: “Send” and “Don't send”;
- it to wait for your answer, even if you take an hour to give it;
- it to send nothing if you don't answer.
What n8n has built in
n8n can already put a workflow on hold. Some nodes, like Gmail or Slack, have an operation that sends a message and waits for the reply, and the Wait node can resume execution on a webhook call. That's great if you live in Slack or your inbox. Just think about the timeout: a request you ignore shouldn't hang forever, or pass for an approval.
If you want the question on your phone, with buttons that answer in one tap, and a deadline that counts as a no, an external API like Aval's does the job with a plain HTTP Request node.
Step 1: the API key
Open your Aval account and create an API key. In n8n, add a credential of type “Header Auth”: name Authorization, value Bearer followed by your key. That way the key doesn't show up in plain text in the workflow.
Step 2: ask the question
Add an HTTP Request node:
- method
POST, URLhttps://www.taraxe.com/api/aval/questions?wait=45; - authentication: the Header Auth credential from step 1;
- JSON body, with the question, the options and the context.
{
"question": "Send this reply to {{ $json.client }}?",
"options": ["Send", "Don't send"],
"context": "{{ $json.draft }}",
"agent_name": "n8n · support",
"expires_in_minutes": 240
}If the draft may contain quotes or line breaks, fill in the body field by field instead (“Using Fields Below”): n8n then takes care of escaping the text.
The question goes out right away, on Telegram and by email. Thanks to ?wait=45, the request waits up to 45 seconds for the answer. It returns an object with a status: answered if you've already replied, otherwise pending and a question_id.
Step 3: wait for the answer
If the answer isn't there yet, you need to check again until it arrives. A small loop does it:
- an If node that tests whether
{{ $json.status }}equalspending; - if true, an HTTP Request node doing a
GETonhttps://www.taraxe.com/api/aval/questions/{{ $json.question_id }}?wait=45, with the same credential, then back to the If node; - if false, move on.
Each check waits up to 45 seconds on its own, so the loop doesn't hammer the server. Checking a question costs nothing. For a long deadline, several hours for example, you can slip a Wait node of a few minutes into the loop.
Step 4: act on the answer
After the loop, a Switch node looks at the status and the answer:
statusisansweredandansweris “Send”: send the email;- anything else, including
expiredandcancelled: send nothing, and optionally keep the draft aside.
If you wrote a note when answering, it comes through in the comment field. You can pass it to the model so it fixes the draft.
Frequently asked questions
What happens if I never answer?
At the deadline, the question expires and the check returns expired. The workflow leaves the loop and, with the Switch described above, sends nothing.
How much does it cost?
Each question asked costs one credit, and the first 20 are free. Waiting and checking the answer are free. Packs range from €10 for 100 questions to €50 for 1,000, with no subscription.
What about Make or Zapier?
Same idea: an HTTP module that sends the question with ?wait=45, then checks again as long as the status is pending.