SAP IDoc Nodes
Exchange SAP IDocs from a pipeline — post goods movements, deliveries, orders and invoices into SAP ECC / S/4HANA on-premise, and decode the production orders, deliveries and acknowledgments SAP pushes back — using the functions you built on the connection's SAP IDoc connector page.
Configuration Quick Reference
| Field | What you choose | Details |
|---|---|---|
| Parameters | Connection, Function, Function Parameters, Delivery Mode | Select the SAP IDoc connection profile, the function to run, and bind its ((parameter)) values with expression support. Delivery Mode appears on the two write nodes. |
| Settings | Description, Timeout (seconds), Retry on Timeout, Retry on Fail, On Error | Node description, maximum execution time, retry behavior, and error-handling strategy. All execution settings default to pipeline-level values. |
The Five Node Types
Unlike most connectors, SAP IDoc splits into one node type per operation, because the operations do genuinely different things — two of them never touch SAP at all.
| Node | Node type | Contacts SAP? | Purpose |
|---|---|---|---|
| Parse IDoc-XML | connected.sap_idoc.parse | No | Decode raw IDoc-XML into structured JSON |
| Build IDoc-XML | connected.sap_idoc.build | No | Serialize an IDoc to IDoc-XML from a template, segment JSON, or raw |
| Send IDoc to SAP | connected.sap_idoc.send | Yes | POST one IDoc to SAP, auto-filling the control record |
| Send IDoc Batch | connected.sap_idoc.send_batch | Yes | POST several IDocs (one basic type) as a single bundled packet |
| Save as Template | connected.sap_idoc.save_template | No | Turn a parsed IDoc into a reusable Send skeleton with ((placeholder)) markers |
Each node's Function picker offers only functions of its matching type, so a Send node cannot accidentally run a Parse function.
The connector has no trigger. Receiving an IDoc from SAP is a Webhook Trigger followed by a Parse IDoc-XML node — SAP's WE21 XML HTTP port POSTs the IDoc-XML to the webhook URL, and the parse node decodes it. See Receiving IDocs from SAP for the full wiring, including the SAP-side SM59 / WE21 / WE20 configuration it depends on.
Node Configuration
| Field | Type | Required | Description |
|---|---|---|---|
| Connection | Select | Yes | The SAP IDoc connection profile to use |
| Function | Select | Yes | The saved function of this node's type |
| Function Parameters | Expression fields | Depends on function | One field per ((placeholder)) the function declares — see Parameter templating tips |
| Delivery Mode | Select | No | Send and Send Batch only: On Failure (default — try immediately, buffer only if SAP is unreachable), Always (every call goes through the Store & Forward buffer), Off (synchronous only; failures surface directly to the pipeline) |
| Delivery order | Radio | No | Send and Send Batch only, when Delivery Mode is not Off: Connector default (any order for these operations), In order, or Any order (fastest). See Store & Forward |
Downstream nodes read the result via $node["<node name>"].result, and execution facts (success, functionId, durationMs, timestamp) under $node["<node name>"]._metadata. The result object is exactly the function's own response shape — the sections below name every key each node delivers.
Node Outputs
Parse IDoc-XML
// $node["Parse IDoc"].result
{
"count": 1,
"basicType": "LOIPRO01",
"messageType": "LOIPRO",
"idocNumber": "0000000000098765",
"idocs": [
{
"basicType": "LOIPRO01",
"controlRecord": {
"segment": "EDI_DC40",
"fields": { "MESTYP": "LOIPRO", "SNDPRN": "P01CLNT100", "RCVPRN": "MAESTROHUB", "DIRECT": "1" }
},
"segments": [
{
"name": "E1AFKOL",
"segmentNo": "1",
"fields": { "AUFNR": "000070004711", "AUART": "PP01", "WERKS": "1000", "GAMNG": "100.000", "GMEIN": "EA" },
"children": [ /* … nested segments … */ ]
}
]
}
]
}
count is how many IDocs the packet held. The three summary keys — result.basicType, result.messageType and result.idocNumber — describe the first IDoc only, and are absent when the packet was empty; result.idocNumber is also absent when that IDoc's control record carries no DOCNUM. idocs has one entry per <IDOC> block, so a bundled packet from SAP yields several. See the connector guide for the full parsed example.
Common downstream expressions:
| Goal | Expression |
|---|---|
| Route by document type | {{ $node["Parse IDoc"].result.messageType }} |
| Reach a top-level segment | {{ $node["Parse IDoc"].result.idocs[0].segments.find(s => s.name === "E1AFKOL") }} |
| Read a control-record field | {{ $node["Parse IDoc"].result.idocs[0].controlRecord.fields.SNDPRN }} |
| Count IDocs in a packet | {{ $node["Parse IDoc"].result.count }} |
segments is an ordered array, and SAP's segment order can differ between releases and configurations. Use .find(s => s.name === "E1AFKOL") rather than segments[0], and .filter(...) for repeated segments such as line items.
Build IDoc-XML
// $node["Build IDoc"].result
{
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MBGMCR03>\n <IDOC BEGIN=\"1\">\n …",
"byteCount": 1314
}
result.xml is the serialized document and result.byteCount its length. Feed {{ $node["Build IDoc"].result.xml }} into an SMB Write, FTP Upload, or REST Request node when the destination wants a file or a non-SAP endpoint rather than SAP's inbound handler.
build is generic by design — it does not apply control-record automation and does not set DIRECT, SNDPRN, RCVPRN, or DOCNUM. Only Send and Send Batch do. If you build XML and post it yourself, you own the envelope.
Send IDoc to SAP
// $node["Send Goods Movement"].result — SAP's answer
{
"httpStatus": 200,
"ackTitle": "IDoc-XML-inbound ok",
"message": "SAP accepted the IDoc (technical ack: \"IDoc-XML-inbound ok\")."
}
// $node["Send Goods Movement"]._metadata — the four every connected node carries, plus the call's own facts
{
"success": true, "functionId": "…", "durationMs": 412, "timestamp": "2026-09-07T08:30:00Z",
"method": "sap_idoc.send", "connectionId": "5f1c8a02-…", "protocol": "sap_idoc",
"mode": "structured", "basicType": "MBGMCR03", "messageType": "MBGMCR"
}
| Expression | Description |
|---|---|
$node["Name"].result.httpStatus | SAP's HTTP status. A 200 alone does not mean acceptance — the acknowledgement title is the real answer |
$node["Name"].result.ackTitle | SAP's technical acknowledgement title, read out of the response body |
$node["Name"].result.message | The acknowledgement in words, ready to log or forward |
$node["Name"]._metadata.mode | structured when the IDoc came from a template or segment JSON, raw for verbatim passthrough |
$node["Name"]._metadata.basicType | The basic type that was posted — absent in raw mode, where you own the envelope |
$node["Name"]._metadata.messageType | The message type from the control record — absent in raw mode |
$node["Name"]._metadata.method | The function that ran, sap_idoc.send here |
$node["Name"]._metadata.connectionId | The connection the post went through |
$node["Name"]._metadata.protocol | Always sap_idoc |
The result is SAP's answer; the facts about the call ride along under _metadata, next to the four every connected node carries — the execute RPC has carried a connector's metadata to the pipeline since #5019.
Send IDoc Batch
// $node["Post Shift Movements"].result — SAP's answer
{
"httpStatus": 200,
"ackTitle": "IDoc-XML-inbound ok",
"message": "SAP accepted the IDoc (technical ack: \"IDoc-XML-inbound ok\")."
}
// $node["Post Shift Movements"]._metadata — the four every connected node carries, plus the call's own facts
{
"success": true, "functionId": "…", "durationMs": 412, "timestamp": "2026-09-07T08:30:00Z",
"method": "sap_idoc.send_batch", "connectionId": "5f1c8a02-…", "protocol": "sap_idoc",
"idocCount": 24, "basicType": "MBGMCR03"
}
result.httpStatus, result.ackTitle and result.message mean the same as on the single Send, as do _metadata.method, _metadata.connectionId and _metadata.protocol. _metadata.idocCount is how many IDocs the packet carried and _metadata.basicType the type they all share. The acknowledgment covers the whole packet, not each IDoc individually.
Save as Template
// $node["Templatize"].result
{
"placeholders": ["ENTRY_QNT", "MATERIAL"],
"template": {
"basicType": "MBGMCR03",
"controlRecord": { "segment": "EDI_DC40", "fields": { "MESTYP": "MBGMCR" } },
"segments": [
{
"name": "E1BP2017_GM_ITEM_CREATE",
"fields": { "ENTRY_QNT": "((ENTRY_QNT))", "MATERIAL": "((MATERIAL))", "PLANT": "1000" }
}
]
}
}
result.template is the IDoc with the requested fields turned into ((placeholder)) markers, ready to feed a Send node; result.placeholders names the markers that were applied, in order.
Parameter Templating Tips
SAP IDoc function parameters are populated the same way as every other connector node:
((token))placeholders inside the function's configuration are replaced with the values you set on the node — the same((paramName))syntax used when authoring the function.{{ ... }}expressions let you use JavaScript plus the pipeline context objects ($input,$node,$trigger,$execution) to compute each value.- Outside
{{ }}, a value starting with$is a shorthand lookup into the upstream data packet —$.payload.deliveryNote.
MaestroHub resolves {{ }} first, then the $ shorthand, before substituting into the function's ((placeholder)).
As on every node, $input resolves to an array of the immediate upstream node(s)' outputs, not a single object. Use $input[0].<field>, or reference a node by name with $node["Upstream Node"].result.<field> to avoid depending on edge order.
Feeding a whole object or array
Three parameters take structured values rather than strings, and each supports a whole-field binding:
| Function | Parameter | Whole-field binding | Bind it to |
|---|---|---|---|
| Send / Build | idoc | ((idoc)) | An object in the IDoc JSON shape |
| Send Batch | idocs | ((idocs)) | An array of such objects |
| Send / Build (template mode) | the items key inside values | "items": "((lineItems))" | An array of row objects, one per line item |
The engine JSON-encodes the bound value and the connector decodes it back, so an upstream array survives the round trip and expands into one segment per element. For example, binding lineItems to {{ $node["Aggregate Pallets"].result.rows }} emits one E1BP2017_GM_ITEM_CREATE segment per row. An empty array emits zero item segments — header segments still render.
Dates and units
Two formatting rules cause most late SAP rejections; compute them in the expression, not in SAP:
// Date: YYYYMMDD, no separators
{{ new Date().toISOString().slice(0,10).replace(/-/g,'') }} // "20260729"
Units of measure must be the ISO code (PCE, KGM, LTR), not SAP's internal code (EA, ST, KG). The full set of field-format rules is in the connector guide.
Store & Forward
Send IDoc to SAP and Send IDoc Batch are write operations and are eligible for Store & Forward. The other three nodes are pure transforms and have no Delivery Mode.
| Delivery Mode | Behavior |
|---|---|
| On Failure (default) | Post immediately; buffer only when SAP is unreachable, then deliver the buffer once it recovers |
| Always | Every IDoc goes through the durable buffer first |
| Off | Synchronous only — a failed post surfaces directly to the pipeline with no buffering |
Delivery order. Send and Send Batch do not ask for in-order delivery, so the node's Delivery order setting, left at Connector default, means any order: when SAP refuses a buffered IDoc, it is retried behind newer ones and the newer ones keep flowing. If SAP must post your IDocs in sequence, for example a goods movement that depends on an earlier one, set Delivery order to In order. Then nothing behind a refused IDoc is sent until you retry it, skip it or move the backlog to Failed messages.
This matters more than usual for SAP: ERP maintenance windows are scheduled and routine, while the shop floor keeps producing goods movements. With Store & Forward on, a window becomes a pause rather than a set of lost postings.
A buffered IDoc is delivered later, and SAP's technical ack is evaluated then. Business posting remains asynchronous either way — see Error Handling below.
Error Handling
The node's Settings tab provides the same Timeout / Retry on Timeout / Retry on Fail / On Error controls documented on the Nodes page.
The connector classifies every send outcome so retries only happen where they can help:
| Situation | Outcome | Retried |
|---|---|---|
200 with an IDoc-XML-inbound ok title, or 200 with no title | success | — |
200 with an IDoc-XML-inbound not ok title | permanent | No |
401 / 403 — credentials or IDoc authorization | permanent | No |
409 — duplicate sender IDoc number | permanent | No |
Other 4xx | permanent | No |
5xx, 408, 429 | transient | Yes |
| Network, DNS, TLS, or timeout failure | transient | Yes |
SAP's plain XML-HTTP handler returns 200 even when it rejects the document; the real answer is in the response body's <title>. The connector reads that title, so a rejected IDoc is a failed node with a remediation message pointing at WE20 — never a silent success. The raw title is available at $node["…"].result.ackTitle.
A green Send node means SAP received and structurally accepted the IDoc. Whether SAP actually posted the business document happens later and asynchronously (status 53 posted / 51 error). Do not treat a successful node as a confirmed material document, delivery, or invoice.
To close the loop, configure SAP's ALEAUD acknowledgment path and handle the resulting ALEAUD01 IDocs on your webhook pipeline — the full pattern with a working example is in the connector guide.
Pipeline Patterns
Post a document into SAP
Trigger (Webhook / MQTT / OPC UA / Schedule)
└─► Set or JavaScript (normalize to the item shape)
└─► Send IDoc to SAP (template MBGMCR, Delivery Mode: On Failure)
Receive a document from SAP
Webhook Trigger (Raw Body Mode on, auth header matching SM59)
└─► Parse IDoc-XML xml = (($trigger._metadata.raw_body))
└─► Switch on $node["Parse IDoc"].result.messageType
├─ LOIPRO ─► JavaScript ─► UNS Publish
├─ DELVRY ─► JavaScript ─► SQL Insert
└─ ALEAUD ─► IF status 53 / 51 ─► confirm or alert
Batch at end of shift
Schedule Trigger
└─► SQL Query (movements buffered since the last run)
└─► JavaScript (map rows to IDoc JSON)
└─► Send IDoc Batch (idocs = ((idocs)), Delivery Mode: Always)
└─► SQL Update (mark submitted)
File-based EDI in and out
Schedule Trigger ─► SMB List ─► SMB Fetch
└─► Parse IDoc-XML (a codec-only connection works here — no SAP endpoint needed)
└─► JavaScript (validate / enrich)
└─► Send IDoc to SAP (segment JSON mode, from the parsed IDoc)
└─► SMB Move (archive)
Fully worked versions of these — with real payloads, bindings, and the SAP-side configuration each depends on — are in Real-World Use Cases.