Documentation
n8n Drop-In
Download n8n Drop-In
Download the workflow JSON, import it into n8n, and wire your irreversible actions through PASS/WARN/BLOCK.
Preview
100%
n8n workflow preview
How it works
test The N8N drop in can be used as a main workflow or as a sub-workflow.
Workflow JSON
Total downloads: 2
Download JSON
{
  "nodes": [
    {
      "parameters": {
        "amount": "={{ $json.poll_delay_seconds }}\n"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -5120,
        -1136
      ],
      "id": "37dce79e-0142-4e92-86aa-60eda2069e90",
      "name": "WAIT – Approval Pending",
      "webhookId": "07d30b80-864e-43c7-9526-2cd01c289e58"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "53a95118-0ad0-442c-a91c-f83032c36f85",
              "name": "decision_id",
              "value": "={{$json.decision_id}}",
              "type": "string"
            },
            {
              "id": "9e7c61a4-ab1d-4f80-9989-a7ce1f952d3b",
              "name": "approval_poll_count",
              "value": "={{$json.approval_poll_count || 0}}",
              "type": "number"
            },
            {
              "id": "6a2f73d3-8f86-4c2a-b15a-f17eb61b6292",
              "name": "approval_token",
              "value": "={{$json.approval_token}}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -4944,
        -1136
      ],
      "id": "0e78f677-5d2b-4d65-9e5d-b65b755b9e1d",
      "name": "Pin Approval State"
    },
    {
      "parameters": {
        "url": "={{ \n  'https://aisafegate.com/api/decisions/' \n  + $json.decision_id \n  + '/approval'\n  + '?execution_id=' + $execution.id\n}}\n",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Approval-Token",
              "value": "={{$json.approval_token}}"
            }
          ]
        },
        "options": {
          "timeout": 15000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -4592,
        -1136
      ],
      "id": "f8791292-692b-4a4b-a3d9-42d65ec72cbb",
      "name": "Poll Approval",
      "credentials": {
        "httpBearerAuth": {
          "id": "8rS1s3rwg9I4A7dr",
          "name": "Bearer Auth account 2"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "d8d19512-8c94-44e0-b611-8be9cd8d7746",
              "leftValue": "=$json.approved === true",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            },
            {
              "id": "82e71568-808f-40bc-a63e-eff84905d14c",
              "leftValue": "$json.decision_id",
              "rightValue": "= $node[\"Pin Approval State\"].json.decision_id",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "e23ccc82-5ade-4993-afd9-4c70b84f1fe1",
      "name": "Is Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -5072,
        -896
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "7e76860e-d9bf-444d-93a4-f32a15cec607",
              "name": "approval_poll_count",
              "value": "={{$json.approval_poll_count + 1}}",
              "type": "number"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -4480,
        -896
      ],
      "id": "d309b0f3-6011-4ea6-9819-c1cd6042e940",
      "name": "Increment Poll Count"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "836b4956-ecc7-4135-ba88-ed8cdecf5ade",
              "leftValue": "={{ ($json.final_gate_status ?? $json.status) === 'PASS' }}",
              "rightValue": "PASS",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5872,
        -864
      ],
      "id": "4e753e24-81ce-4912-a82d-d59b3db4155c",
      "name": "Is PASS?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "1264ccdf-0d2b-452c-8688-c28c76139312",
              "name": "decision_id",
              "value": "={{$json.decision_id}}",
              "type": "string"
            },
            {
              "id": "46ce61de-4520-4512-a8db-a5018dc882e1",
              "name": "approval_started_at",
              "value": "={{new Date().toISOString()}}",
              "type": "string"
            },
            {
              "id": "8b342b55-752d-41be-9ab8-ca7516c04be3",
              "name": "approval_poll_count",
              "value": "=0",
              "type": "number"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -5488,
        -1136
      ],
      "id": "578ec522-4d50-45d2-9d24-5f5f7ee04034",
      "name": "Init Approval State"
    },
    {
      "parameters": {
        "errorMessage": "Safety Gate unavailable or invalid response — stopping for safety."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -6112,
        -896
      ],
      "id": "8c935b90-0989-426d-877d-cc221dbb1161",
      "name": "STOP – Gate Unavailable"
    },
    {
      "parameters": {
        "errorMessage": "Approval API returned invalid response (missing approved boolean). Stopping for safety."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -4912,
        -1376
      ],
      "id": "a715a887-b566-4bf1-a71d-00ca259d1432",
      "name": "STOP – Approval API Error"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "2093582b-31d1-41e5-96cd-9e05ecf6e4d0",
              "leftValue": "={{    ($json.final_gate_status ?? $json.status) === 'WARN'    && !!$json.decision_id  }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5664,
        -1136
      ],
      "id": "34f3f629-2865-46e8-8a41-8011ecdd4811",
      "name": "WARN has decision_id?"
    },
    {
      "parameters": {
        "errorMessage": "=Blocked by Safety Gate.\nReason: {{$json.reason || 'Policy violation'}}\nDecision ID: {{$json.decision_id || 'n/a'}}\n\n"
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -5632,
        -1376
      ],
      "id": "7f38caf9-9f07-40eb-9843-16db750b0b8f",
      "name": "Blocked by Safety Gate."
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "0f2c8dc2-f243-444d-8679-4d375331803c",
              "leftValue": "={{ Date.now() - Date.parse($json.approval_started_at) }}",
              "rightValue": "={{ 60 * 60 * 1000 }}",
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -4880,
        -896
      ],
      "id": "02ed2dd8-4d13-4fe4-8833-9580722371f9",
      "name": "Approval Time Expired?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "9623da71-eafe-4eaa-8f9a-9b91413e37a9",
              "name": "decision_id",
              "value": "{{ $node[\"Pin Approval State\"].json.decision_id }}",
              "type": "string"
            },
            {
              "id": "3bd221a2-4aaa-438b-938a-eb622af6242d",
              "name": "approval_poll_count",
              "value": "={{ $node[\"Pin Approval State\"].json.approval_poll_count }}",
              "type": "number"
            },
            {
              "id": "9b90966e-e43c-4318-b75c-81ecf8641281",
              "name": "approval_started_at",
              "value": "={{ $node[\"Init Approval State\"].json.approval_started_at }}",
              "type": "string"
            },
            {
              "id": "9be78a52-22ff-42c7-acb0-d292c5337bff",
              "name": "approved",
              "value": "={{ $json.approved }}",
              "type": "boolean"
            },
            {
              "id": "90faef31-55b8-4aef-97d0-0a980b0c78c3",
              "name": "approval_loop_iteration",
              "value": "={{$json.approval_poll_count}}",
              "type": "number"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -4432,
        -1136
      ],
      "id": "39b1246c-88a7-44c6-ba82-a4c7adc808ff",
      "name": "Reattach Approval State"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "e4f0b219-ee99-4751-b564-614434ac38dc",
              "leftValue": "={{$json.approval_poll_count}}",
              "rightValue": 20,
              "operator": {
                "type": "number",
                "operation": "gte"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -4688,
        -896
      ],
      "id": "3a7e0373-0c4c-419a-8ebb-7ff4b8e035d8",
      "name": " Approval Expired? (poll count)"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "9bcb2d44-6d15-4253-ae90-a48a03d4f804",
              "leftValue": "={{$json.approval_token}}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -4768,
        -1136
      ],
      "id": "a56ac6ed-367c-477d-b485-e37da1e72a9e",
      "name": "Approval Token Present?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "89323900-b16f-4c1c-923c-8a45c81ad459",
              "name": "poll_delay_seconds",
              "value": "=Math.min(\n  $json.approval_poll_count < 2 ? 10 :\n  $json.approval_poll_count < 5 ? 30 :\n  60,\n  60\n)\n",
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -5312,
        -1136
      ],
      "id": "547bd7c6-80dc-4dbb-9a6c-49a099ee8980",
      "name": "Calculate Poll Delay"
    },
    {
      "parameters": {
        "content": "## Action Blocked\n",
        "height": 192,
        "width": 1472,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5696,
        -1424
      ],
      "id": "452b5554-a80e-4a6d-a71f-f314b70d44d5",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Blocked Check\n\n",
        "height": 208,
        "width": 208,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5920,
        -1424
      ],
      "id": "8925285c-5086-42dc-b52b-54f01c39236a",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "## Action Warning\n\n",
        "height": 512,
        "width": 1440
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5712,
        -1216
      ],
      "id": "31cac2c2-1edc-4fe6-9c67-073153e30c27",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "## Warning Check\n\n",
        "height": 224,
        "width": 192
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5920,
        -1184
      ],
      "id": "bfc881ab-c8f3-4345-9b5d-6349fb441fa7",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "## Passed Check\n\n",
        "height": 208,
        "width": 192,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5920,
        -928
      ],
      "id": "8c6c4862-a7aa-4431-8cd5-38f6987c4637",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "content": "## Action Passed\n\n\n",
        "height": 272,
        "width": 688,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5440,
        -688
      ],
      "id": "b1b9db96-abbd-45dd-882b-ebf29a116a04",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "75685fb7-529a-43fc-a403-2dfa6054a787",
              "name": "approval_source",
              "value": "={{   $json.approved === true     ? \"human\"     : \"policy\" }}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -5376,
        -592
      ],
      "id": "e47f9103-8750-4f74-88e3-923bce397e35",
      "name": "CONTINUE — Action Authorized (PASS)"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "565090db-1ad4-4774-817f-acbc2345cc3e",
              "name": "final",
              "value": true,
              "type": "boolean"
            },
            {
              "id": "449b457a-c637-4e62-b0d9-0bb89ae62313",
              "name": "status",
              "value": "\"PASS\"",
              "type": "string"
            },
            {
              "id": "35b6e016-e66a-4cc1-9033-60fb78472fe6",
              "name": "decision_id",
              "value": "={{ $json.decision_id }}",
              "type": "string"
            },
            {
              "id": "891c1fd5-5ab7-470b-bcac-440e8e8f9abf",
              "name": "execution_id",
              "value": "={{ $execution.id }}",
              "type": "string"
            },
            {
              "id": "7d1372c0-d057-4b23-a94b-4132bb82132e",
              "name": "action",
              "value": "={{ $json.ai_output }}",
              "type": "string"
            },
            {
              "id": "f90dbe86-a3fe-4b04-ae15-c3490ac45957",
              "name": "execution_authorized",
              "value": true,
              "type": "boolean"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -4992,
        -592
      ],
      "id": "8e1ab68d-0c9f-4c81-85b2-9fea21462f0a",
      "name": "EXECUTE — Approved Action"
    },
    {
      "parameters": {
        "errorMessage": "=APPROVAL_TIMEOUT\nApproval not granted within review window.\nExecution stopped (fail-closed).\n"
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -4544,
        -1376
      ],
      "id": "a5763ca5-5eb2-47a9-9ecc-b8444a739bcc",
      "name": "STOP — Approval Timeout Reached"
    },
    {
      "parameters": {
        "errorMessage": "WARN status returned without decision_id — cannot enter approval flow. Failing closed for safety."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -5248,
        -1376
      ],
      "id": "d16bbba1-1aad-4d73-ac29-14630c13d3b0",
      "name": "STOP — Decision Error"
    },
    {
      "parameters": {
        "content": "## \nWARN — Execution paused pending human approval\n",
        "height": 80,
        "width": 400
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -5184,
        -1216
      ],
      "id": "e985f82b-7124-4790-a9a0-f14e2c035c97",
      "name": "Sticky Note7"
    },
    {
      "parameters": {
        "errorMessage": "Approval token missing — cannot poll approval safely."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -4720,
        -1376
      ],
      "id": "5e0ed9a2-7b81-4a2d-9ff1-f510790e8dd6",
      "name": "STOP — Approval Token Error"
    },
    {
      "parameters": {
        "errorMessage": "=Invalid safety gate outcome received.\nExpected PASS, WARN, or BLOCK.\nExecution stopped (fail-closed).\n"
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -5440,
        -1376
      ],
      "id": "9e833aef-113e-4974-a9de-8ab1753766af",
      "name": "STOP — Invalid Safety Outcome"
    },
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        -7136,
        -992
      ],
      "id": "b24dac08-f836-412a-914b-4032b63fa992",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "content": "## Validate Safety Gate Response\n\n\n",
        "height": 416,
        "width": 384,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -6336,
        -1168
      ],
      "id": "ea9fcb6f-d690-4961-9e74-7034e1b6816e",
      "name": "Sticky Note8"
    },
    {
      "parameters": {
        "errorMessage": "Missing required actionKind.  Every request must explicitly declare the policy category (e.g. money.refund, data.export, identity.role_change).  Execution stopped (fail-closed)."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -6288,
        -896
      ],
      "id": "bda8d5ce-4a94-47e9-b528-5b01c8edbe45",
      "name": "STOP — Missing actionKind"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://aisafegate.com/api/validate",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json }}",
        "options": {
          "timeout": 15000
        }
      },
      "id": "a6f91cd7-975a-4117-9993-edd7cdfc828d",
      "name": "AI Safety Gate — Validate",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        -6272,
        -1088
      ],
      "credentials": {
        "httpBearerAuth": {
          "id": "8rS1s3rwg9I4A7dr",
          "name": "Bearer Auth account 2"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "dfa797a4-4284-4a55-b094-373c4f78e16f",
              "leftValue": "={{ [\"PASS\",\"WARN\",\"BLOCK\"].includes($json.final_gate_status || $json.status) }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -6112,
        -1088
      ],
      "id": "76012928-a6ee-40a6-9ae5-33f6e1823ed9",
      "name": "Valid Safety Gate Outcome?"
    },
    {
      "parameters": {
        "content": "## ## Required Input (Caller Responsibility)\n\nUpstream workflow must provide:\n- context.actionKind (required)\n- ai_output (string or object)\n\nOptional fields depend on actionKind:\n- money.refund → amount_usd, transaction_id\n- identity.role_change → target_user_id, new_role\n- data.export → resource, export_format\n\nMissing required fields will WARN or BLOCK.\n",
        "height": 288,
        "width": 480
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -6896,
        -1392
      ],
      "id": "c1ffc734-ec7e-4cc3-b47d-3d6a4d9f2f4a",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "fd0d9fbc-5086-4561-8ada-e3e4214d5fe2",
              "leftValue": "={{ $json.context.enforcement_mode }}",
              "rightValue": "strict",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            },
            {
              "id": "35679929-6948-4eb9-a5ea-b6c0f1f24404",
              "leftValue": "={{ $json.context.fail_closed }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -6720,
        -992
      ],
      "id": "ecf703d3-6c36-4052-b903-c4c38bd06434",
      "name": "Assert Strict Mode"
    },
    {
      "parameters": {
        "errorMessage": "Strict enforcement is required.  This workflow must run with: - enforcement_mode = \"strict\" - fail_closed = true  Execution stopped to prevent unsafe behavior."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -6544,
        -912
      ],
      "id": "fcdba720-ad66-4c76-a9a6-55d5c82a8fe5",
      "name": "STOP — Strict Mode Required"
    },
    {
      "parameters": {
        "content": "",
        "height": 336,
        "width": 576,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -6944,
        -1088
      ],
      "id": "0ef41ccb-8957-4e4e-a8ee-4896b619b93c",
      "name": "Sticky Note9"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "ee5407de-1ef6-4ece-bcc4-7ab5a97bd9f4",
              "leftValue": "={{ $json.context.actionKind }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -6544,
        -1072
      ],
      "id": "c7a23284-6b3c-495a-b7ad-8c658871704c",
      "name": "Validate Policy Intent (actionKind)"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "29595ef6-f0ae-4a8f-aae7-77f145b83a91",
              "leftValue": "={{    !!$node['Pin Approval State']    && $json.decision_id === $node['Pin Approval State'].json.decision_id  }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5456,
        -896
      ],
      "id": "1767e91c-f867-4ae1-9f6c-bfac0abe917f",
      "name": "Approval Matches Decision?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "c996ff83-2e7a-4593-a9ff-16b78ac70c6d",
              "leftValue": "={{ \n  Boolean(\n    $json.execution_authorized === true &&\n    (\n      (($json.final_gate_status ?? $json.status) === \"PASS\") ||\n      (\n        (($json.final_gate_status ?? $json.status) === \"WARN\") &&\n        $json.approved === true\n      )\n    )\n  )\n}}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5200,
        -576
      ],
      "id": "21b90ef7-1276-4801-ba24-4925d7e0f7b8",
      "name": "Final Authorization Check"
    },
    {
      "parameters": {
        "errorMessage": "Execution blocked by policy enforcement.  The action did not satisfy final authorization requirements under AI Safety Gate evaluation.  No execution was permitted."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -4368,
        -1376
      ],
      "id": "d83ec2ce-976b-4102-b115-f1719071b51c",
      "name": "STOP — Execution Not Authorized"
    },
    {
      "parameters": {
        "errorMessage": "Approval flow entered for non-WARN decision. Failing closed."
      },
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        -5072,
        -1376
      ],
      "id": "8c94a786-d43b-49eb-94ba-9dc164474721",
      "name": "Stop and Error"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "da81552d-e998-4ffe-8139-f295f6cabb0e",
              "leftValue": "={{ typeof $json.approved === 'boolean' && $json.decision_id === $node['Pin Approval State'].json.decision_id }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5232,
        -896
      ],
      "id": "22e1baf2-c1a7-4be2-9bae-aac826bf6b49",
      "name": "Approval Response Valid?1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "47aa6cd5-20c1-4c19-ac03-4b770cd61500",
              "leftValue": "={{    ($json.final_gate_status ?? $json.status) === 'WARN'    && $json.approved !== true  }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "0b9c9d86-b3d1-4b23-bf80-cf1802487c7b",
      "name": "Is WARN?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -5872,
        -1104
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "be471c37-a265-4469-97a5-02bf6ec58010",
              "leftValue": "={{ $json.final_gate_status || $json.status }}",
              "rightValue": "WARN",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            },
            {
              "id": "0eb140da-4694-4192-9160-444d684adf02",
              "leftValue": "={{ $json.approved }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              }
            },
            {
              "id": "488aacb2-daf3-43e5-80ce-976828fa5c43",
              "leftValue": "={{ $json.decision_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -5632,
        -880
      ],
      "id": "55f59b8a-517e-47cf-9114-e8e269e31b2a",
      "name": "Still WARN?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "ef1ef2b7-f90f-4889-bb56-11867c02f1b5",
              "leftValue": "={{ ($json.final_gate_status ?? $json.status) === 'BLOCK' }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "e71dc30c-1c2c-4965-ba3c-0fcaccc28f68",
      "name": "Is BLOCK?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -5872,
        -1344
      ]
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={{ ({\n  ai_output: $json.ai_output || $json.output || {},\n\n  context: {\n    request_id: $execution.id,\n    account_id: $json.context?.account_id || \"acct_demo\",\n    actor_user_id: $json.context?.actor_user_id || \"system\",\n\n    actionKind:\n  $json.context?.actionKind ??\n  $json.context?.action_kind ??\n  null,\n\n    amount_usd: $json.context?.amount_usd ?? null,\n    currency: $json.context?.currency ?? \"USD\",\n    transaction_id: $json.context?.transaction_id ?? null,\n    invoice_id: $json.context?.invoice_id ?? null,\n    refund_reason: $json.context?.refund_reason ?? null,\n\n    target_user_id: $json.context?.target_user_id ?? null,\n    new_role: $json.context?.new_role ?? null,\n    auth_change_type: $json.context?.auth_change_type ?? null,\n    admin_action: $json.context?.admin_action ?? null,\n\n    resource: $json.context?.resource ?? null,\n    data_type: $json.context?.data_type ?? null,\n    scope: $json.context?.scope ?? null,\n    export_format: $json.context?.export_format ?? null,\n    retention_days: $json.context?.retention_days ?? null,\n\n    message_type: $json.context?.message_type ?? null,\n    recipient_count: $json.context?.recipient_count ?? null,\n    webhook_url: $json.context?.webhook_url ?? null,\n    broadcast: $json.context?.broadcast ?? false,\n\n    integration_name: $json.context?.integration_name ?? null,\n    integration_scope: $json.context?.integration_scope ?? null,\n\n    workflow_name: $json.context?.workflow_name ?? null,\n    workflow_action: $json.context?.workflow_action ?? null,\n\n    infra_action: $json.context?.infra_action ?? null,\n    public_exposure: $json.context?.public_exposure ?? false,\n    secrets_touched: $json.context?.secrets_touched ?? false,\n    logging_change: $json.context?.logging_change ?? false,\n\n    case_id: $json.context?.case_id ?? null,\n    support_action: $json.context?.support_action ?? null,\n\n    idempotency_key:\n      $json.context?.idempotency_key || `auto_${$execution.id}`,\n\n    source: \"n8n\",\n    enforcement_mode: \"strict\",\n    fail_closed: true\n  }\n}) }}",
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -6896,
        -992
      ],
      "id": "17d8fc9a-44b2-4d47-b30a-987e051f19fb",
      "name": "Prepare Safety Input (FIXED)"
    }
  ],
  "connections": {
    "WAIT – Approval Pending": {
      "main": [
        [
          {
            "node": "Pin Approval State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pin Approval State": {
      "main": [
        [
          {
            "node": "Approval Token Present?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Approval": {
      "main": [
        [
          {
            "node": "Reattach Approval State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Approved?": {
      "main": [
        [
          {
            "node": "CONTINUE — Action Authorized (PASS)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Approval Time Expired?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Increment Poll Count": {
      "main": [
        [
          {
            "node": "WAIT – Approval Pending",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is PASS?": {
      "main": [
        [
          {
            "node": "CONTINUE — Action Authorized (PASS)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Invalid Safety Outcome",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Init Approval State": {
      "main": [
        [
          {
            "node": "Calculate Poll Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WARN has decision_id?": {
      "main": [
        [
          {
            "node": "Init Approval State",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Decision Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Time Expired?": {
      "main": [
        [
          {
            "node": "STOP — Approval Timeout Reached",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": " Approval Expired? (poll count)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reattach Approval State": {
      "main": [
        [
          {
            "node": "Still WARN?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    " Approval Expired? (poll count)": {
      "main": [
        [
          {
            "node": "STOP — Approval Timeout Reached",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Increment Poll Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Token Present?": {
      "main": [
        [
          {
            "node": "Poll Approval",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Approval Token Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Poll Delay": {
      "main": [
        [
          {
            "node": "WAIT – Approval Pending",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CONTINUE — Action Authorized (PASS)": {
      "main": [
        [
          {
            "node": "Final Authorization Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Prepare Safety Input (FIXED)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Safety Gate — Validate": {
      "main": [
        [
          {
            "node": "Valid Safety Gate Outcome?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Valid Safety Gate Outcome?": {
      "main": [
        [
          {
            "node": "Is PASS?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Is WARN?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Is BLOCK?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP – Gate Unavailable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assert Strict Mode": {
      "main": [
        [
          {
            "node": "Validate Policy Intent (actionKind)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Strict Mode Required",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Policy Intent (actionKind)": {
      "main": [
        [
          {
            "node": "AI Safety Gate — Validate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Missing actionKind",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Matches Decision?": {
      "main": [
        [
          {
            "node": "Approval Response Valid?1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Stop and Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Final Authorization Check": {
      "main": [
        [
          {
            "node": "EXECUTE — Approved Action",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Execution Not Authorized",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Response Valid?1": {
      "main": [
        [
          {
            "node": "Is Approved?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP – Approval API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is WARN?": {
      "main": [
        [
          {
            "node": "WARN has decision_id?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "STOP — Invalid Safety Outcome",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Still WARN?": {
      "main": [
        [
          {
            "node": "Approval Matches Decision?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Stop and Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is BLOCK?": {
      "main": [
        [
          {
            "node": "Blocked by Safety Gate.",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Safety Input (FIXED)": {
      "main": [
        [
          {
            "node": "Assert Strict Mode",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "14b72ae29f280f80f775850858543e56ae3809bb474746406d582c6adc70c61f"
  }
}
Legal & Responsibility Notice
Summary
Informational only
Provided for general guidance. Not legal, compliance, security, or professional advice.
You control implementation
You are responsible for policies, prompts, integrations, workflows, and regulatory requirements.
Liability limitation
To the maximum extent permitted by law, the company disclaims liability for losses arising from use of this documentation or implementations based on it.