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%

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
{
"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.