Recipe · n8n, Node-RED & Make

Human approval in your n8n flow — no Twilio, no WABA.

Your flow reaches the step that spends money, deletes records or emails a customer — and you want a human to say yes first. n8n's native WhatsApp node wants Meta or Twilio credentials, business verification and template approval before it sends anything. pingwa is one HTTP Request node and a join message: the flow POSTs /v1/ask, your phone buzzes with buttons, the flow waits for your tap.

Native WhatsApp Business node

  • Create a Meta developer app
  • Get a WhatsApp Business Account (WABA)
  • Pass business verification
  • Get message templates approved
  • Or route it all through Twilio
Setup: days

pingwa

  • Send join on WhatsApp
  • Get an API key back instantly
  • Drop in one HTTP Request node
Setup: 60 seconds

Honest note: if you already run a WABA and message customers, the native node is the right choice — that's what it's for. pingwa is for the other case: the flow asking you, its operator, for a decision.

§ 1

The workflow: three nodes

Manual Trigger → HTTP Request → IF. The HTTP Request node POSTs your question to /v1/ask and long-polls — the flow genuinely pauses there until you answer or 90 seconds pass. The IF node then branches on which button you tapped. Swap the Manual Trigger for whatever actually starts your flow.

import the template
Download
pingwa-ask.n8n.json
Import
n8n → Workflows → ⋯ → Import from File
Key
set PINGWA_KEY as an environment variable on the n8n host. On n8n Cloud, $env is blocked in expressions (it fails with an opaque “access denied” error) — create a Header Auth credential there instead (name Authorization, value Bearer pw_...) and attach it to the node.

The HTTP Request node's settings, spelled out — this is all the template contains:

http request node — settings
Method
POST
URL
https://pingwa.dev/v1/ask
Header
Authorization: =Bearer {{ $env.PINGWA_KEY }} (the leading = is workflow-export notation — in the UI you toggle the value field to Expression and type the rest)
Body (JSON)
{"text": "Approve this step?", "buttons": ["approve", "reject"], "timeout": 90}
Timeout
95000 ms — a hair over the 90 s the API will hold the question open

timeout: 90 in the body is the maximum the API accepts; the node's own 95 s timeout just makes sure n8n outlasts the long-poll instead of cutting it off. Put anything you like in text — an n8n expression interpolating the item being approved works fine.

§ 2

Branch on the answer

A successful response looks like this — button_id is positional: b0 is the first button you passed, b1 the second.

200 response from /v1/ask
{
  "message_id": 123,
  "billing_class": "template",
  "answered": true,
  "reply": {"answer_id": 124, "text": "approve", "button_id": "b0",
            "created_at": "2026-07-16T14:03:07Z"}
}

So the IF node's condition is a plain string-equals: left value {{ $json.reply.button_id }}, right value b0. True branch = approved, false branch = rejected.

If the ask lands outside your 24h reply window (likely, for approvals that arrive out of the blue), the buttons arrive as a numbered list instead of tap buttons — replying 1 (or the button's text, approve) works the same and still maps to b0.

If nobody answers within the 90 seconds, /v1/ask returns HTTP 408 and the HTTP Request node errors. Treat that as a reject — silence should never approve anything. Wire the node's error output to the same path as the false branch (enable “Settings → On Error → Continue (using error output)”). The question was still delivered to your phone; a late tap is retrievable afterwards via GET /v1/messages/<id>/reply if your flow wants a second look.

§ 3

Node-RED variant

Same shape: a function node prepares the request, an http request node (set to POST, “return a parsed JSON object”) makes the call, and a second function (or switch) node branches on the button.

function node → http request node
// function node BEFORE the http request node
msg.url = "https://pingwa.dev/v1/ask";
msg.method = "POST";
msg.headers = {
  "Authorization": "Bearer " + env.get("PINGWA_KEY"),
  "Content-Type": "application/json"
};
msg.payload = {text: "Approve this step?", buttons: ["approve", "reject"], timeout: 90};
return msg;
function node AFTER the http request node
// output 1 = approved, output 2 = rejected (set the node to 2 outputs)
if (msg.statusCode === 200 && msg.payload.reply.button_id === "b0") {
  return [msg, null];
}
return [null, msg];  // includes the 408 nobody-answered case → fail-safe reject
§ 4

Make.com

In Make, it's the generic HTTP module (“Make a request”): POST the same JSON to /v1/ask with the same Authorization: Bearer header, then add a Router with a filter on reply.button_id equals b0 for the approved route and a fallback route for everything else — rejections and timeouts alike.

§ 5

FAQ

How do I get an n8n WhatsApp approval without Twilio?

Use a plain HTTP Request node instead of the WhatsApp Business node: POST to https://pingwa.dev/v1/ask with your question and buttons (template above, importable). pingwa carries the message over its own official Meta Cloud API number, so you never touch Twilio, a WABA or Meta credentials — you just send join once to get an API key.

Does this work with n8n's send-and-wait?

It is the send-and-wait: POST /v1/ask long-polls, so the HTTP Request node itself holds the flow until the human answers (or 90 s pass). You don't need a separate Wait node, a webhook resume URL, or any special node type — the one HTTP call sends the question and returns with the answer.

What if nobody answers?

After 90 seconds /v1/ask returns HTTP 408 and the node errors. Route the error output to your rejected path — fail-safe means silence never approves. The question stays on the phone, and a late reply can still be fetched with GET /v1/messages/<id>/reply.

Does it work on self-hosted n8n?

Yes — this recipe is outbound-only HTTPS from your n8n host to https://pingwa.dev. No inbound webhook, no public URL, no tunnel needed: the reply comes back on the same long-polled request. A homelab n8n behind NAT works exactly like a cloud one.

QR code to join pingwa on WhatsApp

Scan the code and get instant access. It opens WhatsApp with “join” ready to send, and your API key comes straight back.

Approvals are exactly the messages you want rare and deliberate — the free plan's 30 paid messages a month cover a lot of “Approve this step?”. Your button-tap replies inside the 24h window are free.