AxonFlow API integration for n8n. Call the AxonFlow policy and HITL endpoints directly from your n8n workflows.
This package contributes a single AxonFlow node with four operations against an AxonFlow Agent:
| Operation | Endpoint | When to use |
|---|---|---|
| Check Policy | POST /api/v1/mcp/check-input |
Before a workflow takes a sensitive action — receive {allowed, block_reason?} and branch on it. A deny either stops the workflow with an error that names the reason, or is output as an item with allowed: false, set by On Deny; see What the node emits below. On a redact-not-block allow it also returns the masked text; see Redaction: your workflow must use the masked text below. |
| Record Decision | POST /api/v1/audit/tool-call |
After a successful action — capture inputs, outputs, policies applied. |
| Audit Log | POST /api/v1/audit/tool-call |
From error branches — record the failed action with success: false and error_message. |
| Wait for Approval | POST /api/v1/hitl/queue |
AxonFlow Enterprise only. Creates an approval request and returns at once with its approval_id; it does not pause the workflow. Pair it with an n8n Wait node to pause. |
Plus a single AxonFlow API credential type holding the endpoint + Basic-auth (clientId + userToken).
The node reads the platform's HTTP status and its response body, and decides in one place what they mean.
| AxonFlow answers | Check Policy emits | Any other operation |
|---|---|---|
| 2xx | the response body as the item, unchanged | the response body (Wait for Approval: approval_id (the request UUID), request_id, status, expires_at) |
403 with allowed: false (a policy deny) |
depends on On Deny (below): the response body as the item (allowed: false, block_reason, decision_id, policy_matches), or an error AxonFlow denied the request: <block_reason> (decision <id>) |
an error quoting the platform |
| 401 | an error: AxonFlow rejected the credential (HTTP 401): <platform text>. Check the Client ID and User Token ...; when the platform says user_token_required, AxonFlow refused the request (HTTP 401): this organization requires a per-user token, which the n8n node does not send: ... |
the same |
| 402 | an error: AxonFlow refused the request: a tier limit of this deployment was reached (HTTP 402): <platform text> |
the same |
| 429 | an error: AxonFlow refused the request: a rate limit was reached (HTTP 429, limit_type "...", resets at ..., retry after N s): <platform text>, with each detail only when the platform sends it |
the same |
| 404 | an error quoting the platform | Wait for Approval: AxonFlow has no approval queue at this endpoint (HTTP 404): /api/v1/hitl/queue is served by AxonFlow Enterprise only ... |
any other 4xx, including a 403 without allowed: false |
an error: AxonFlow refused the request (HTTP <status>): <platform text> |
the same |
| 5xx, or no answer | Failure Mode: Open (the default): an item {_axonflow_unreachable: true, governance: "unavailable", cause: "http_503" or "no_response", error, operation}. Closed: an error. |
the same |
Every error is rethrown under both failure modes; only a 5xx or no answer is swallowed by Open. So n8n's Retry On Fail sees a 429, and Continue On Fail turns an error into an item with error.
On Deny: stop, or output an item to branch on. Check Policy has an On Deny option, and its default depends on the node's version:
- A node added from this release on (node version 2) defaults to Output an Item to Branch On. Put an IF on
{{ $json.allowed }}before any action the policy guards: without one, the workflow continues past a deny. - A node in a workflow saved before this release (node version 1) keeps Stop the Workflow With an Error, which is what a deny did on AxonFlow v8 and later (the platform answers a deny with HTTP 403, and the node stopped on it). On those platforms a saved workflow keeps its behaviour; what changes is the error text, which now names the reason and the decision instead of n8n's
Forbidden - perhaps check your credentials?(and so does theerrora Continue On Fail item carries). Two exceptions, both in the stopping direction: against an AxonFlow older than v8, which answered a deny with HTTP 200 andallowed: false, a version-1 node used to output that item and now stops; and a version-1 node is not upgraded to version 2 unless you replace it.
Set On Deny explicitly to choose either behaviour on either version. Only the value Output an Item to Branch On outputs a deny; any other value, including an expression that resolves to nothing, stops the workflow.
Branch on allowed. With On Deny set to output, a deny, including one whose block_reason starts unknown_constraint; (a policy needs an attribute the request did not carry, and the rest of the text names the policy and the attribute) or approval_required:, arrives as an item with allowed: false, so an IF node on {{ $json.allowed }} takes its false branch and can read block_reason.
The Open fallback item has no allowed key, on purpose. An IF on {{ $json.allowed }} is true does not take its true branch during an outage; check {{ $json.governance }} if the workflow should treat "AxonFlow did not decide" differently from a deny.
Approvals on AxonFlow v11. On the planes this node calls, a policy that requires approval does not hold the request: Check Policy answers a deny whose block_reason starts approval_required. Holding for a reviewer happens on AxonFlow's workflow and multi-agent planes, not here. Wait for Approval creates an approval request on AxonFlow Enterprise and returns immediately; on Community the route does not exist and the node says so.
Check Policy can allow an action and still require that you change it. When the statement you submitted carried sensitive data under a redact-not-block policy, AxonFlow allows the call and returns the masked version alongside it:
{
"allowed": true,
"redacted": true,
"redaction_evaluated": true,
"redacted_statement": "transfer to [REDACTED]"
}This node passes those fields through to your workflow unchanged, and does nothing else with them. It does not rewrite the action, and it cannot: the node has no way to know which of your downstream parameters the statement came from. Applying the redaction is your workflow's job.
So when redacted_statement is present, use it in place of the original. A
workflow that branches only on allowed will proceed with the unmasked text,
and the platform's audit record will show a redaction that your workflow did not
apply.
Two rules worth building in:
- Treat
redaction_evaluatedas the trust signal. When it is absent or false the redaction detector did not run, so "no masked text" means "nothing looked", not "nothing found". Fail closed there rather than proceeding. - AxonFlow will not redact for you. Substituting the masked text it returns is the sanctioned way to satisfy a redaction policy; masking the text yourself is not, because your patterns and the platform's will disagree.
This applies on every AxonFlow edition. On Community the call is allowed and recorded either way, so this paragraph is the control - nothing downstream will stop an unmasked value for you. On Enterprise the platform can additionally refuse a call whose enforcement point has declared it cannot apply a redaction; this node declares exactly that, honestly, because it performs no substitution of its own.
- Settings > Community Nodes > Install.
- npm package name:
@axonflow/n8n-nodes-axonflow. - Restart n8n.
cd ~/.n8n/custom
npm install @axonflow/n8n-nodes-axonflow
# restart n8nA node installed under ~/.n8n/custom registers as CUSTOM.axonFlow, not @axonflow/n8n-nodes-axonflow.axonFlow, so the shipped example workflow (which names the GUI install's type) cannot find it. Import a copy with the type rewritten:
sed 's/"@axonflow\/n8n-nodes-axonflow\.axonFlow"/"CUSTOM.axonFlow"/' examples/governed-loan-workflow.json > governed-loan-workflow.custom.jsonInstalling into ~/.n8n/nodes (cd ~/.n8n/nodes && npm install @axonflow/n8n-nodes-axonflow) keeps the package type, like the GUI install.
n8n Cloud does not currently allow unverified community nodes. Use the stock-HTTP-node recipe on n8n Cloud until this package is verified.
Credentials > New > AxonFlow API.
| Field | Description |
|---|---|
| Endpoint | Base URL of your AxonFlow Agent. SaaS: https://try.getaxonflow.com. Self-hosted: typically port 8080. |
| Client ID | Your tenant identifier. |
| User Token | Sent as the password half of HTTP Basic auth. Stored encrypted in n8n. |
- Install the community node (see above).
- Create an AxonFlow API credential with your endpoint + Client ID + User Token.
- Add an AxonFlow node to your workflow.
- Pick an operation:
- Check Policy — submit a proposed action; with On Deny set to output (the default for a new node), branch on
allowed: true/false. - Record Decision — log the outcome of a downstream action.
- Audit Log — log a failed action from an error branch.
- Wait for Approval — create a HITL request (AxonFlow Enterprise); it returns at once, so pair it with a Wait node to pause.
- Check Policy — submit a proposed action; with On Deny set to output (the default for a new node), branch on
- Run the workflow.
- Bearer Auth > Header Auth. This credential uses the Header Auth pattern (Authorization built inline) rather than n8n's built-in Bearer Auth class, which silently drops the header in some n8n versions (n8n#15261).
- Idempotency by default. Every operation sends
Idempotency-Key: {executionId}-{itemIndex}-{runIndex}-{nodeName}-{requestHash}so n8n'sRetry on Faildoesn't double-record: a retry of the same call sends the same key (unless a parameter's expression changes between attempts, such as{{ $now }}, which changes the request body and so the key). The run index and a hash of the request body are part of it because AxonFlow replays its stored answer for a repeated key without comparing request bodies, so inside a loop a key without them would hand a later iteration the decision made for an earlier statement. (Keys changed shape in this release, so a retry that spans an upgrade of the node is not deduplicated once.) AxonFlow accepts only the charactersA-Z a-z 0-9 _ . : - /in a key, up to 256 of them, so each other character of the node name becomes_and a short hash of the original name follows it (a name already inside that set is used as it is), and a key longer than 256 characters is cut and ends with a hash. Override at the node parameter level if you need a domain-specific key; a key you set is sent exactly as you wrote it, so keeping it inside that set is up to you, and AxonFlow refuses one outside it with HTTP 400, which the node quotes. - HITL pairs with the Wait node.
Wait for Approvalcreates the AxonFlow approval entry (Enterprise) and returns immediately; it does not pause anything itself. Pair it with a downstream Wait node configured for On Webhook Call mode, which is what pauses the workflow. As of platform v8.1.0+, pass the Wait node's webhook URL asnotify_urlin the HITL queue request and AxonFlow will POST to it automatically on approval/rejection — no polling sidecar needed. For self-hosted deployments on v8.0.x, two manual paths work: (a) run a small polling sidecar that watchesGET /api/v1/hitl/queue/{id}and POSTs to the Wait node's webhook URL when status changes, or (b) have a reviewer trigger the resume URL manually from the portal. See the n8n integration docs for details.
Every call this node makes to AxonFlow carries X-Axonflow-Client: n8n-plugin/<version>, set once on the credential so it rides every operation. The version is read from this package's own metadata.
What this is and is not. It is attribution on a request the platform already receives — no additional request is made, and this node sends no heartbeat or telemetry ping of its own. It is never used for authentication: the platform authenticates on the Authorization header, so a missing or mangled value cannot fail a call. Nothing about your workflow data, statements, parameters, or identity is added by it.
examples/governed-loan-workflow.json — an importable workflow that:
- Receives a loan request via HTTP trigger,
- Calls Check Policy on the amount,
- If
allowed=false, branches to Wait for Approval, which creates the approval request and returns, then to a Wait node, which pauses the workflow until the reviewer's decision arrives at its webhook, - On approval, calls the downstream loan-issuance HTTP endpoint,
- Records the outcome with Record Decision, with an error branch to Audit Log.
Import in n8n: Workflows > Import from File > governed-loan-workflow.json.
git clone https://github.com/getaxonflow/axonflow-n8n-node.git
cd axonflow-n8n-node
npm install
npm run build # tsc > dist/
npm run lint
npm test # node --test (133 tests)n8n-workflow is pinned to exactly 2.11.1 on purpose. From 2.12.0 the package depends on isolated-vm, a native module whose Node floor (22, then 24) is above this package's CI matrix (Node 18, 20 and 22), so a routine bump breaks npm ci there. Compatibility with the n8n release this node targets (2.38.7) is proven by the runtime legs, which run the pinned n8nio/n8n:2.38.7 image and CLI, not by these unit types.
- n8n + AxonFlow Integration Guide — full walkthrough including the stock-HTTP-node recipe, HITL polling sidecar, and idempotency details.
- AxonFlow — main project site.
- AxonFlow on GitHub — community edition.
MIT