Approvals & decision tables
FormNode approvals run over email. The approver gets a clean message with context and one-click approve/reject buttons — no portal login, no password reset, no "another vendor I have to remember." When they decide, FormNode calls a webhook back into n8n with the result so your workflow can resume automatically.
Worked example: a firmware upgrade approval
An n8n workflow watches SonicWall's firmware feed. When a new release lands, the workflow lists each customer's affected firewalls and asks for written approval before scheduling the upgrade. Here's how that gets wired with FormNode approvals.
1. Create the approval form
In the FormNode dashboard, create a form for the customer organization named Firmware Upgrade Approval. Add the fields you want shown in the approval card — typically Static Content for the explanation, Info Card for the device list, and an optional Multi-Line Inputfor "notes from approver."
Open the Webhookpill on the canvas and configure the form's automation webhook — the URL n8n will use to resume the workflow once the approval is decided. We'll reuse this URL on the approval itself, so you don't have to pass it manually each time.
2. Trigger an approval from n8n
From your firmware-detection workflow, POST to FormNode's approvals endpoint for the form, with the approver's email and a context object describing what they're signing off on:
POST https://app.formnode.io/api/v1/forms/{formId}/approvals
Authorization: Bearer fn_sk_...
Content-Type: application/json
{
"contextData": {
"company": "Acme",
"maintenance_window": "Sunday Nov 16, 2:00–6:00 AM CST",
"summary": "SonicWall firmware 7.1.3 → 7.2.1 across 4 firewalls"
},
"sendTo": "client@example.com",
"callbackUrl": "https://your-n8n.example.com/webhook/firmware-callback",
"reminders": { "schedule": [2, 5], "finalWarning": true }
}Anything in contextData renders inside the approval email so the approver sees the same details n8n already gathered. sendTo is the approver's email address. Skip callbackUrlif you want FormNode to use the form's configured automation webhook (recommended for GUI-built forms). Pass it explicitly only when you need a one-off destination such as an n8n Wait/Resume URL. reminders.schedule is an array of day offsets (1–365, strictly increasing); each entry sends a reminder email that many days after the initial send.
3. The approver decides
The approver gets an email signed from your branded sender (custom SMTP on Pro and above), with the context card and two buttons: Approve and Reject. Both buttons go to a public, signed URL — no FormNode login required. Optionally they can leave a note before deciding.
4. n8n receives the callback
When the approver clicks, FormNode POSTs to your callback URL with the decision. The body uses camelCase keys (matching the rest of FormNode's webhook payloads):
{
"eventType": "approval.responded",
"approvalId": "8f2a4e1c-6b7d-4f3a-9e8d-1c2b3a4d5e6f",
"formId": "5a8b3c2d-1e4f-4a9b-8c7d-6e5f4a3b2c1d",
"status": "responded",
"decision": "approved",
"comments": "Approved for the Sunday window. Skip BR-FW-02.",
"contextData": {
"company": "Acme",
"maintenance_window": "Sunday Nov 16, 2:00–6:00 AM CST"
},
"responseData": {
"decision": "approved"
},
"respondedAt": "2026-04-25T18:42:11.337Z",
"respondedBy": null,
"respondentInput": {
"email": "client@example.com",
"name": null
}
}status is FormNode's internal lifecycle state (typically responded for a normal answer); decisionis the approver's actual choice. They're kept separate so you can distinguish a normal response from edge cases like an expired-and-still-clicked link. responseData carries any extra fields the approver filled in beside the decision button — useful for forms that ask for a comment or a scheduled date as part of the approval.
Your n8n workflow picks this up — typically via a Wait → Resume on Webhook node — and continues with the upgrade if approved or notifies the technician if rejected.
Decision tables: per-row decisions
Sometimes an approval isn't a single yes/no. The customer might want to approve the firmware upgrade on three of four firewalls and reject the fourth because they're replacing it next quarter. That's a decision table: a list of items where each row gets its own approve/reject and an optional schedule.
Add a decision table to a form
In the form builder, drop a Table field and configure its columns — typically asset_name, asset_type, and any context columns the approver needs (e.g., last_updated, uptime). Then in the table's settings panel, toggle Decision table. Two per-row controls appear automatically: a Decision dropdown (Approve/Reject) and an optional Scheduled-for datetime.
Pass the rows in when creating the approval
When the n8n workflow creates the approval, send the device list as rows. The same approvals API accepts a rowsarray; each row gets its own controls in the email and in the approver's decision page.
The callback
When the approver decides, the callback uses the same approval.responded envelope shown above. The per-row decisions live in responseData, keyed by the decision table's field name. n8n iterates the array, schedules approved rows for the time the customer picked, and surfaces rejected rows for the technician to triage.
Reminders and expiration
Each approval can be configured with a reminder schedule — an array of day offsets (e.g., [2, 5] sends reminders 2 and 5 days after the initial send) — and an expiresAt timestamp. Reminders require sendTo to be set; FormNode tracks delivery and stops sending once the approval is decided or expires.
Troubleshooting
Approver says they didn't get the email
Open the approval in the FormNode dashboard and confirm the approval is still pending, has the expected recipient, and has not expired. If mail is not arriving, check your SMTP provider or switch to your custom SMTP on Pro.
Callback never fires
Approvals only call back after a decision is recorded. If you're testing, the approval has to actually be approved or rejected. Check the approval callback status, attempt count, last error, and next retry fields in the dashboard or API, then compare them with the receiving workflow execution.
Approver clicked the link but it says "already decided"
Each approval link is single-use by design — once decided, subsequent clicks show the recorded decision. If the customer wants to change their mind, they reply to the email or you reissue a new approval.