Aval

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.

· by Antoine

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, URL https://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 }} equals pending;
  • if true, an HTTP Request node doing a GET on https://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:

  • status is answered and answer is “Send”: send the email;
  • anything else, including expired and cancelled: 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.