Skip to main content
Version: 3.0 (next)

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​

FieldWhat you chooseDetails
ParametersConnection, Function, Function Parameters, Delivery ModeSelect 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.
SettingsDescription, Timeout (seconds), Retry on Timeout, Retry on Fail, On ErrorNode 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.

NodeNode typeContacts SAP?Purpose
Parse IDoc-XMLconnected.sap_idoc.parseNoDecode raw IDoc-XML into structured JSON
Build IDoc-XMLconnected.sap_idoc.buildNoSerialize an IDoc to IDoc-XML from a template, segment JSON, or raw
Send IDoc to SAPconnected.sap_idoc.sendYesPOST one IDoc to SAP, auto-filling the control record
Send IDoc Batchconnected.sap_idoc.send_batchYesPOST several IDocs (one basic type) as a single bundled packet
Save as Templateconnected.sap_idoc.save_templateNoTurn 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.

There is no SAP IDoc trigger node

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​

FieldTypeRequiredDescription
ConnectionSelectYesThe SAP IDoc connection profile to use
FunctionSelectYesThe saved function of this node's type
Function ParametersExpression fieldsDepends on functionOne field per ((placeholder)) the function declares — see Parameter templating tips
Delivery ModeSelectNoSend 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 orderRadioNoSend 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:

GoalExpression
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 }}
Find segments by name, not by index

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 does not fill the control record

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"
}
ExpressionDescription
$node["Name"].result.httpStatusSAP's HTTP status. A 200 alone does not mean acceptance — the acknowledgement title is the real answer
$node["Name"].result.ackTitleSAP's technical acknowledgement title, read out of the response body
$node["Name"].result.messageThe acknowledgement in words, ready to log or forward
$node["Name"]._metadata.modestructured when the IDoc came from a template or segment JSON, raw for verbatim passthrough
$node["Name"]._metadata.basicTypeThe basic type that was posted — absent in raw mode, where you own the envelope
$node["Name"]._metadata.messageTypeThe message type from the control record — absent in raw mode
$node["Name"]._metadata.methodThe function that ran, sap_idoc.send here
$node["Name"]._metadata.connectionIdThe connection the post went through
$node["Name"]._metadata.protocolAlways 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)).

$input is an array

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:

FunctionParameterWhole-field bindingBind it to
Send / Buildidoc((idoc))An object in the IDoc JSON shape
Send Batchidocs((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 ModeBehavior
On Failure (default)Post immediately; buffer only when SAP is unreachable, then deliver the buffer once it recovers
AlwaysEvery IDoc goes through the durable buffer first
OffSynchronous 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.

Buffering does not change the acknowledgment model

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:

SituationOutcomeRetried
200 with an IDoc-XML-inbound ok title, or 200 with no titlesuccess—
200 with an IDoc-XML-inbound not ok titlepermanentNo
401 / 403 — credentials or IDoc authorizationpermanentNo
409 — duplicate sender IDoc numberpermanentNo
Other 4xxpermanentNo
5xx, 408, 429transientYes
Network, DNS, TLS, or timeout failuretransientYes
HTTP 200 does not mean the IDoc was accepted

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 successful Send node is not a posted SAP document

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.