Description
n8n-nodes-nx3
This is an n8n community node. It lets you query and update Sage X3 from your
n8n workflows — read, list, create, modify and describe objects, and run SQL
SELECT queries.
IntellX for Sage X3 talks to Sage X3’s CAdxWebServiceXmlCC SOAP web service
through the XCHATX3OBJ sub-program (ChatX3 patch). You work entirely with JSON —
the node builds the SOAP request, asks X3 to answer in native JSON, and returns a
clean, ready-to-use object. No XML wrangling required.
n8n is a fair-code licensed workflow automation platform.
Installation
Operations
Credentials
Object parameters
SQL operations
Output
Advanced options
Use as an AI Agent tool
Compatibility
Usage examples
Troubleshooting
Resources
Version history
Installation
Follow the installation guide in the n8n community nodes documentation.
In short, from your n8n instance: Settings → Community Nodes → Install, then enter n8n-nodes-nx3.
Self-hosted (Docker) manual install
If you run n8n in Docker and want to load this package directly, mount the built package into the container’s custom extensions folder:
docker run -d --name n8n -p 5678:5678
-v n8n_data:/home/node/.n8n
-v /path/to/n8n-nodes-nx3:/home/node/.n8n/custom/n8n-nodes-nx3:ro
n8nio/n8n
Build the package first with npm install && npm run build, then restart the container.
Operations
| Operation | X3 action | Description |
| — | — | — |
| Read Sage X3 Object | READ | Read an object by its identifier and return its full field tree |
| List Sage X3 Objects | LIST | List records of an object, with optional selection criteria |
| Create Sage X3 Object | CREATE | Create a new object from a JSON payload |
| Modify Sage X3 Object | MODIFY | Update fields of an existing object |
| Describe Sage X3 Object | DESC | Get the local-menus and field metadata of an object class |
| Custom Sage X3 Action | (free text) | Send any XACTION the patch exposes, including future ones |
| SQL Analyse | ANALYSE | Check that a SQL query is valid, without returning rows |
| SQL Select | SELECT | Execute a SQL SELECT and return the rows |
| Run Sub-Program (Advanced) | (raw XML) | Call any X3 sub-program with a raw input payload (escape hatch) |
The Action Code field is always visible and pre-filled from the operation you
pick, so you can see exactly which XACTION is sent — and override it if needed.
> Table-type objects are not handled by the ChatX3 patch yet.
Credentials
You authenticate with your Syracuse user (the same credentials you use to log into Sage X3), via HTTP Basic Authentication.
Prerequisites
- A reachable Sage X3 server exposing the SOAP endpoint
- A Syracuse user with the required function rights on the objects you intend to read/create/modify
- The
XCHATX3OBJsub-program published in your X3 environment (ChatX3 patch) - Sage X3 Object Code — the object code, e.g.
ITM(items),BPC(customers),SOH(sales orders). - Transaction Code — X3 transaction (
XTRANSACTION); leave empty for the default. - Identifier — the object’s primary key (
XIDENT). Required for Read and Modify. For Create it must usually match the key field in the data (e.g.ITM0.ITMREF) unless X3 generates it. Optional for Custom, hidden for List and Describe. - Data (JSON) — the payload sent as
XDATAJSON. Shown for Create, Modify, List (selection criteria) and Custom. - All fields are dimensioned, so values are arrays:
"TSICOD": ["20"]or"TSICOD": ["20","21","99"]. - Target a specific index by adding
(n)to the field name:"TSICOD(1)": "21". - Don’t fill table footer/count variables —
NBLIGand friends are filled automatically. - Dates use
"YYYY-MM-DD", e.g."SBSDAT": ["2026-05-01"]. - Clear a field with an empty string
"", a0integer, or a"0000-00-00"date.
Credential fields (IntellX for Sage X3 API)
| Field | Required | Description |
| — | — | — |
| Base URL | ✅ | Scheme + host (+ port) of the X3 server, e.g. https://my-x3-host:8124. The SOAP path is appended automatically. |
| Username | ✅ | Syracuse user |
| Password | ✅ | Syracuse password |
| Code Language | | Default codeLang for the SOAP call context (e.g. FRA, ENG). Defaults to FRA. |
| Pool Alias | | Default poolAlias (e.g. POOL_SEED). Must match an existing, started X3 connection pool. |
| Pool ID | | Default poolId (usually left empty). |
| Request Config | | Default requestConfig. The node adds the JSON-mode flags automatically. |
| Allow Self-Signed Certificates | | Skip TLS validation. Useful for on-prem X3 with a self-signed certificate; do not enable for production over the Internet. |
The credential Test button calls the WSDL endpoint with your credentials to confirm connectivity.
Object parameters
Shown for Read, List, Create, Modify, Describe and Custom:
Data JSON conventions (from the ChatX3 patch)
Example Create payload:
{
"ITM0": {
"DES1AXX": ["Test item"],
"ITMREF": ["ASS001C"],
"TCLCOD": ["BMSOL"]
}
}
Context (Optional)
An optional envelope merged into XDATAJSON as a top-level context key. Leave
it untouched and nothing is added — the payload stays exactly as it was.
| Option | Effect |
| — | — |
| Language | Override the XCHATX3OBJ language for this call (e.g. ITA). Independent from the SOAP-level codeLang in Advanced Options — different layer. |
| User | Run the call as another user (e.g. FU01). Only honored when the caller has GPROFIL=ADMIN. |
| Response Screens | Return only these screens, e.g. ITM0, ITM1. |
| Response Fields | Return only these fields, e.g. DES1AXX. |
| Include Hidden Fields | Include hidden and technical fields, which are excluded by default. |
Resulting payload:
{
"context": {
"language": "ITA",
"user": "FU01",
"response": { "screens": ["ITM0"], "fields": ["DES1AXX"], "hidden_fields": true }
},
"ITM0": { "DES1AXX": ["Nouvelle designation"] }
}
SQL operations
SQL Analyse validates a query without running it; SQL Select runs it and
returns the rows. Both accept optional Max Lines and Max Time (Seconds) caps,
sent to X3 as context.maxlines and context.maxtime.
> Max Time caps the execution inside X3, while Request Timeout in Advanced
> Options caps the HTTP call (30 s by default). Keep the former below the latter,
> or the request gives up before X3 does.
Query parameters
Rather than concatenating values into the query — unsafe, especially when an AI
Agent supplies them — declare them under Query Parameters and reference them
with {{name}}:
SELECT TOP (100) [USR0], [CREUSR0], [CREDAT_0]
FROM [AUTILIS]
WHERE USR_0 IN ({{logins}})
AND CREDAT_0 BETWEEN {{from}} AND {{to}}
[[AND CREUSR_0 = {{creator}}]]
literal — so never wrap {{name}} in quotes yourself.
[[ ... ]] marks an optional clause: it is dropped entirely when its parameters are empty, and kept otherwise. Ideal for filters an agent may or
may not fill in.
{{name}} used outside an optional clause with no value raises a clearerror rather than silently changing the query.
-- line comment, a / ... / block, or a string literal are left untouched — so commenting a
filter line out while you iterate works exactly as a SQL reader expects.
| Type | Rendering | Use for |
| — | — | — |
| Text | 'value', embedded quotes doubled | =, or a LIKE where you write the pattern yourself |
| Contains | '%value%', with % _ [ inside the value escaped | LIKE {{name}} — type dupont, not %dupont% |
| Number | bare, validated numeric | >, <, >= |
| Date | quoted, YYYY-MM-DD or ISO-8601 | BETWEEN, comparisons |
| Boolean | 1 / 0 | flags |
| List | 'a','b','c' — comma-split, each quoted | IN ({{name}}) |
> Contains escapes the LIKE wildcards contained in the value, so searching
> for remise 50% looks for that exact text instead of matching everything
> starting with remise 50.
> Use List — not Text — for IN ({{name}}). A Text value holding a,b
> becomes the single literal 'a,b' and matches nothing; the node detects that
> case and tells you to switch type. A List value cannot itself contain a comma,
> since the comma is the separator.
Simplify
Sage X3 returns SQL rows with generic keys — Col1, Col2, … — losing the
link to the selected columns. Turn on Simplify (SQL Select only) to get the
rows with their real names restored from your query:
{
"rowCount": 3,
"columns": ["USR0", "CREUSR0", "CREDAT_0"],
"rows": [{ "USR0": "ADMCA", "CREUSR0": "ADMIN", "CREDAT_0": "2015-08-14" }]
}
The envelope stays down to the data itself. success, messages and trace
only appear when something went wrong, so a failure is never silent while the
happy path stays cheap to read — which matters when the rows feed an AI Agent.
Dates are returned as plain YYYY-MM-DD, and X3's 0000-00-00 "not set"
sentinel becomes null — a model reads null as empty, whereas 0000-00-00
looks like a real date. The time part is only dropped when it is exactly
midnight UTC, so a genuine timestamp keeps its full value.
Row Format then chooses the row shape:
{{ $json.rows[0].USR_0 }} and rendered natively by the n8n Table view.
columns. Far more compact, whichmatters when the rows are fed to an AI Agent.
SQL comments are ignored when the column names are read, so a query may open
with a / ... / documentation header and carry comments between two select
items. Quoted values are left alone — a -- inside a string literal stays data.
The renaming is best-effort and never reorders or drops data: with SELECT *,
an unresolvable expression, or any count mismatch, the original Col_N keys are
kept as-is. Leave Simplify off to get the full envelope (data, status,
sessionId, technicalInfos).
Output
Object operations return a clean JSON object:
{
"success": true,
"status": 1,
"action": "READ",
"object": "ITM",
"ident": "ASS001",
"transaction": "",
"data": {
"ITM0": { "ITMREF": "ASS001", "DES1AXX": "Computer server", "TCLCOD": "BMSOL" },
"ITM1": { "EANCOD": "3782940199614", "TSICOD": ["10", "12", "122"] }
},
"messages": [{ "trace": "F1730" }, { "info": "Object created: ASS001" }],
"trace": "F1730",
"sessionId": "6784",
"technicalInfos": { "poolEntryIdx": 6784, "totalDuration": 611 }
}
| Field | Description |
| --- | --- |
| success | true when X3 reports the action succeeded (XRETURNJSON.success, fallback status === 1). |
| status | Raw X3 status (1 = OK, 0 = failure). |
| action / object / ident / transaction | Echo of the request for traceability. |
| data | The object payload (X3 XDATAJSON), parsed into a navigable object. |
| messages | X3 user messages: info, error, alert, and the trace entry. |
| trace | The X3 trace name, surfaced for convenience (also present in messages). |
| sessionId | The X3 pool entry that handled the call. Pass it back as Pool ID Override to chain calls on the same session. |
| technicalInfos | Pool/performance metrics returned by X3. |
> X3 may report success: true while still including an error message (e.g. an access-level check). To gate a workflow strictly, test for errors with an IF node:
> {{ !($json.messages || []).some(m => m.error) }}
SQL Select with Simplify on returns the reduced shape shown above instead.
Advanced options
All optional. The output-shaping options default to on; debug and override
options default to off.
| Option | Default | Purpose |
| --- | --- | --- |
| Compact Single-Value Arrays | on | Unwrap single-element arrays: ["Iconext"] → "Iconext". Multi-value arrays stay arrays. |
| Trim Trailing Empty Values | on | Drop trailing empty values X3 pads dimensioned fields with: ["A","",""] → ["A"]. |
| Request Timeout (Seconds) | 30 | Abort the SOAP call when X3 does not answer, instead of hanging. Surfaces a clear timeout error. |
| Code Language Override | — | Override the credential codeLang (SOAP call context) for this call. |
| Pool Alias Override | — | Override the credential poolAlias for this call. |
| Pool ID Override | — | Pin the call to a specific X3 session (e.g. ={{$json.sessionId}} from a previous step) to preserve object locks across Read → Modify. |
| Public Name Override | — | Call a different sub-program than XCHATX3OBJ. |
| Include Request in Output | off | Add request (the JSON payload sent + the SOAP envelope) for debugging. |
| Include Result in Output | off | Add result (the parsed X3 result payload, navigable) for debugging. |
| Include Raw SOAP Response | off | Add raw (the full SOAP envelope as XML) for low-level transport debugging. |
Use as an AI Agent tool
This node has usableAsTool enabled, so it can be attached to an AI Agent
node — for object operations ("find item BMS009", "create a customer") as well as
SQL Select.
Two ways to wire a SQL tool, with very different safety profiles:
$fromAI on SQL Query. Flexible, butthe model composes the SQL itself and can reach any table.
[[ ... ]] optional clauses and put $fromAI on the Value of each entry in
Query Parameters. The model cannot write SQL, values are escaped by the node,
and unfilled filters disappear on their own. Prefer this one.
Make optional filters actually optional
$fromAI('name', 'description', 'string') produces a mandatory field: n8n
only marks it optional when the call carries a fourth argument, the default
value. Without it the model is forced to supply a value on every call, and an
[[ ... ]] clause can never be dropped — the call is rejected before it even
reaches the node, with Received tool input did not match expected schema.
So for every parameter that backs an optional filter, end the call with an empty
default:
={{ $fromAI('creator', 'Creator code. Leave empty to skip this filter', 'string', '') }}
The red asterisk next to the field in the tool's Test dialog disappears once it
is right. Keep the default off for genuinely required inputs — reading an object
without its identifier makes no sense.
> The JSON schema n8n advertises to the client lists no required fields, but
> the runtime validation still rejects a missing one. A model that correctly
> omits a filter therefore fails on a schema that told it the field was optional.
Error handling
Network failures (timeout, connection refused, unknown host, unreachable network)
are turned into one-sentence actionable messages, so the agent can decide whether
to retry, ask the user, or report the failure instead of hanging.
Compatibility
CAdxWebServiceXmlCC, Apache Axis 1.4 SOAP stack) with the ChatX3 XCHATX3OBJ sub-program.Usage examples
Read an item
Read Sage X3 ObjectITMASS001Modify an item description
Modify Sage X3 ObjectITMASS001{ "ITM0": { "DES1AXX": ["New description"] } }Read → modify on the same X3 session (preserve the lock)
1. A Read Sage X3 Object node returns sessionId.
2. In the following Modify Sage X3 Object node, set Advanced Options → Pool ID Override to ={{ $('Read Sage X3 Object').item.json.sessionId }}.
Filtered SQL Select
SQL Select, Simplify on SELECT TOP (200) [SOHNUM0], [BPCORD0], [ORDDAT_0]
FROM [SORDER]
WHERE 1 = 1
[[AND [BPCORD_0] = {{customer}}]]
[[AND [ORDDAT_0] >= {{from}}]]
customer (Text), from (Date) — leave either empty to drop its clause.Troubleshooting
| Symptom | Likely cause |
| --- | --- |
| self-signed certificate error | Enable Allow Self-Signed Certificates in the credential. |
| Timed out / connection refused / host not found | The X3 server is unreachable — check the credential Base URL, the network, and raise Request Timeout if the server is merely slow. |
| No Pool: | The X3 pool isn't started or the alias is wrong. Start the pool in X3 (Administration → Web services) or fix Pool Alias. |
| Niveau d'accès insuffisant / Insufficient access level | The Syracuse user lacks rights on the object. Grant the function rights in X3. |
| Modification en cours sur un autre poste | A previous READ still holds the object lock. Chain calls with Pool ID Override, or skip the READ and MODIFY directly. |
| Erreur zone [M:...] | Field validation failed — check that Identifier matches the key field in the data, value formats, and category counters. |
| SQL Select returns 0 rows with an IN filter | The parameter is typed Text instead of List, so the values were sent as one single literal. |
Resources
Version history
0.3.0
DESC).screen/field filtering, and hidden fields.
Max Lines / Max Timecaps.
{{name}} placeholders and [[ ... ]] optional clauses, with typed escaping (Text, Number, Date, Boolean,
List).
Row Format switch between Objects and Arrays.
longer hangs when X3 is unreachable.
0.2.0
0.1.0
XCHATX3OBJ, plus an advanced raw Run Sub-Program mode.sessionId / Pool ID Override.usableAsTool for AI Agent integration.