Skip to main content
The Business Central node connects a workflow to Microsoft Dynamics 365 Business Central. Pick an Operation: Look up reads a record in the middle of a run and hands it to the steps after it, Insert creates a record such as a sales order or purchase invoice, Update writes approved values back to an existing record, Post Purchase Invoice posts a verified purchase invoice match against its purchase order, and Confirm Purchase Order applies an order confirmation match to a purchase order. A following step is required after a lookup and optional after a write: a write can end a branch, or hand the created record to the steps after it.

Configuration

Transient delivery failures are retried automatically by the platform. Use the node’s retry field to set the maximum number of attempts, between 1 and 5 (default 3). A posting operation checks its saved operation after an interrupted attempt and stops if Business Central cannot confirm the outcome, so a retry never posts twice.
At least one rule is required in Look up. A lookup with no rules would read the whole table, so the node refuses to save until you add one.

Connector

Pick a connector of type Business Central. The connector supplies the app-only token, environment, and company id, so the node needs no URL or HTTP method: Ingestly builds the request from the connector and the entity you choose. Pointing this node at a QuickBooks connector fails the step rather than quietly reading from QuickBooks. A connector with no base URL, or with no company configured, fails the step with a message naming what is missing: reconnect it or set its company first. See the Business Central guide for how to connect and for advanced request patterns (deep insert, multi-entity $batch, attaching the source document).

Entity selection

The Entity field is a searchable picker populated live from the connector’s OData $metadata. Choose a connector first, then pick from its list of entity sets, for example salesOrders, purchaseInvoices, or customers.
The catalog is read through the connector profile of the environment you are editing in. In a Production workflow the connector’s Production profile must be connected, and in a Development workflow its Development profile. When the catalog cannot load, the schema popover in the editor shows the reason, for example the HTTP status Business Central returned or which profile is not connected.
  • With the catalog loaded, click the refresh action next to the field to re-fetch it after a schema change on the Business Central side.
  • If an entity is not in the list (a custom or extension entity), search for it and choose Use “<name>” to enter it directly.
  • If the catalog fails to load (or none has loaded yet, for example before a connector is chosen), the field falls back to a plain text input with no refresh action: type the entity name directly once the field is no longer disabled.
For a Look up, the picker keeps the full read catalogue; for a write it offers only the entity sets the connector says are writable. The entity has to be a plain identifier: letters, digits and underscores, starting with a letter or an underscore. Spaces and slashes around the name are trimmed off before that check, so /purchaseOrders/ is stored and read as purchaseOrders. A dot, a space inside the name, a slash inside the name, a leading digit, a template expression, or anything else is refused when you save. A name that is nothing but slashes or spaces is refused as a missing entity. That trimming applies to Entity only. An entry in Select or Expand has to be a plain identifier on its own, with no surrounding slashes to strip.

Operation

Look up

Reads a record out of Microsoft Dynamics 365 Business Central in the middle of a run and hands it to the steps after it. Use it to resolve something the document only refers to: extract an invoice, find the purchase order it names, then reconcile the two.

Result

First match (default). Asks Business Central for a single record. The matched record is the payload, so a downstream reference reads a field straight off it: {{FindPO.payload.number}}. When nothing matched, payload is null. All matches. Asks for a page of records. The payload is the array itself, so {{FindPO.payload}} is what a Loop or a $each iterates, and {{FindPO.payload[0].number}} reads the first row. When nothing matched, the payload is an empty array rather than null, so a $each over it is a no-op instead of a resolution failure.
All matches returns at most 100 records, and there is no paging. A query that matches more than 100 returns the first 100 and reports matchCount as 100, so matchCount alone cannot tell a query that matched exactly 100 from one that matched thousands. metadata.businessCentral.truncated is what tells them apart: it is true only when records were left behind. Narrow the rules, or branch on truncated, when the answer has to be complete.

Rules and operators

A rule has a Field, an Operator, a Value and a Value Type. Rules combine with AND: a record has to satisfy every rule to match.
  • Field names a column on the Business Central record, not a path into upstream data. Pick it from the connector’s catalog for the chosen entity, or type it. It has to be a plain identifier, and Business Central’s OData filter has no dot notation, so vendor.name is refused when you save. A template expression in this box is refused too.
  • Value is the template-bearing half, and that is the inverse of a Validate rule. {{extract.payload.po_number}} in the value box is the normal case.
  • Value Type says how the value is written into the query. It describes the connector’s column, not what you type. See Value types.
Business Central publishes twelve operators: Is Empty and Is Not Empty take no value; the value box is hidden for them. Every other operator requires one. Both compare the field against the empty text as well as null, because Business Central returns "" rather than null for a text field that holds nothing. On a number, date or GUID column, use Equals with the column’s blank value instead (0, 0001-01-01, or the all-zero GUID) together with the matching value type.
The QuickBooks node’s Look up operation publishes only nine of these. Not Equals, Is Empty and Is Not Empty have no equivalent in Intuit’s query API, so they are Business Central only. A rule authored here does not necessarily port to a QuickBooks lookup.
Value types
A rule value is written into the OData query as a literal, and OData literals are typed. A quoted literal is text, so totalAmountIncludingTax gt '1250.50' compares a decimal column against a string and Business Central rejects the whole request. Value Type is how you say which literal to write: Ingestly cannot work the type out for you. Business Central’s number column is text and routinely holds 1001, so a value of 1001 is a text comparison on one column and a numeric one on another, and only the column says which. Leave the type on Text unless you know the column is not. A value that does not match its type is refused when you save, naming the shape it expected. A value that is a template is not judged at save time ({{extract.payload.total}} is not a malformed number, it is not a number yet); if it resolves to something that is not a valid literal of that type, the step fails at run time with the same message.
Contains, Starts With and Ends With have no value type. They compile to OData’s text functions, whose argument is always text, so the control is hidden for them and a type set before you switched operators is dropped.The QuickBooks node’s Look up operation has no value types at all. Its query dialect quotes every literal, so there is nothing to choose.
Values that resolve to nothing
A value box is filled in at save time, but it is resolved at run time, and a template can resolve to nothing. For six operators, an empty resolved value would match every record in the table, so the step fails instead:
  • Contains, Starts With, Ends With, Greater Than, Greater Than or Equal and Not Equals refuse an empty resolved value, naming the field and the operator.
  • Equals, Less Than and Less Than or Equal are allowed through, because those stay narrow rather than widening.
  • In List needs at least one non-empty entry after the commas are split.
This is a run-time failure, not a save-time one: a rule using one of those six operators, bound to a field the extract did not produce, saves cleanly and fails when it runs. The other three do not fail. An Equals, Less Than or Less Than or Equal rule whose value resolves to nothing compares the field against an empty string, so the lookup runs and, unless a record’s field is itself blank, reports found as false: a missing extraction reads as “not found”, and nothing tells you the question was never asked. Bind the value to a field you know the upstream step emits, and treat found: false after an Equals rule as “check the extraction” as well as “check the tenant”.
Reserved field names
null, true, false, NaN and INF are literals in OData filter expressions rather than field names, so a rule whose field is exactly one of them is refused when you save. A field called null would compile to null eq null, which matches every record.

Select and Expand

Select limits which fields come back. Leave it empty to take everything the connector sends. Expand pulls a navigation property in with the record, for example purchaseOrderLines, so the lines arrive on the same result instead of needing a second lookup. Both are lists of plain identifiers: pick each name from the connector’s catalog, or type it and choose Add. Neither accepts a dotted path: they name top-level fields and navigation properties, not nested ones. Business Central returns exactly the fields you select and adds nothing. If the record feeds a Business Central node in Update, through a Reconcile or directly, keep id in the list: the write-back reads the record id from this record and fails without it.
Expand is Business Central only. The QuickBooks node’s Look up operation has no such field, because QuickBooks has no OData surface.

When nothing matches

A lookup that matches nothing is a successful step, not an error. The step completes, payload is empty (null in First match, [] in All matches), and metadata.businessCentral.found is false. That is deliberate. “This purchase order does not exist in Business Central” is a business outcome your workflow should route on, not an outage. Only a query that could not be asked fails the step: a bad connector, a rejected query, an HTTP error from Business Central, or a lookup that did not answer within its Timeout (45 seconds unless you set one). Route on it with the node’s own ports. In Look up the node has no plain output: it leaves through one of two ports instead. With Fail if not found off, exactly one of the two fires. Connect the path that uses the record to Found and whatever “we could not find it” should do to Not found: a Review for a human to resolve, a notification, or nothing at all, since a run that leaves through an unconnected port simply stops there and still completes. At least one of the two has to be connected. With Fail if not found on, connect Found to the next step; no matches fail the step instead of taking Not found.

Fail if not found

Enable Fail if not found when a matching record is required, such as the purchase order named on an invoice. With it on, no matches fail the step instead of taking the Not found branch; leave Continue on fail off and the error output unconnected to stop the run. It is off by default, keeping the Found / Not found branches, applies to both result modes, and leaves connection and API errors on their normal error handling.
Do not test for a missing record with an If node that reads {{FindPO.payload.number}}. A no-match payload is null, so a reference through it resolves to nothing, which is the same thing a genuine record with a blank number produces. The Not found port is the routing answer; metadata.businessCentral.found is the field to read when a later step needs the fact inside a template.

Insert

The default operation. Creates a new record from the current document. The body auto-scaffolds a deep insert: a header object with the parent entity’s fields plus a nested line array, built from the columns carried into this step.

Update

Writes changes back to an existing Business Central record. The body is an operations document: a list of operations that each state what to do, not how to send it. Ingestly compiles the list into the connector’s own $batch request; you never write an OData entity-set path, a key-in-parentheses reference, or an HTTP verb.

Record source

Choose where the target record’s id, and its line rows, come from. Reconcile (default, recommended). Ingestly builds the write plan from an upstream Reconcile step’s verified match, and keeps its safety gate.
Line id path and Line id column work together: the server stamps a matched or removed line row’s connector line id only when both are set, reading the id from Line id path and writing it under the Line id column key. If the two disagree (for example, the column renamed to rowId while the body still reads {{$item.lineId}}), the id lands where nothing looks; left blank, line operations resolve their id to nothing. Business Central defaults both fields once a connector and entity are chosen, so leaving them alone is normally correct: open Advanced only if this entity’s line id field differs from the default.
Two safety behaviors apply: if the reconcile result has a blocking mismatch and no approved review, the step fails instead of writing; if nothing changed and there is nothing to send, the step succeeds without sending a request.
Direct (opt-in). No Reconcile node needed. You supply the record id, and optionally the line arrays, directly.
Direct skips the Reconcile safety gate: whatever record id and line references resolve below are written as-is, with nothing verifying them against the source document first. Switch to Reconcile when that verification matters.
For line pairing too complex for a template to express (for example, matching document lines to fetched connector lines by more than one key), add a Transform step upstream that joins the two sides and emits rows carrying both, then point Direct’s Lines field at that array. This keeps the pairing logic in one script instead of a second one inside the connector node.
Direct never fetches the connector record, so {{$writeback.record.*}} has nothing to read: a body that references it under Direct is a design-time error. Bind any field you need from the connector record (an ETag, a last-modified timestamp) from whichever upstream node already supplied the record id instead.

The operations document

The auto-generated body is a list of operations under a top-level operations array: Business Central exposes line items as addressable child records, so a line operation is its own entry: it carries its own entity and id, plus parentEntity and parentId for the parent it belongs to. The two travel together: never one without the other.
$each iterates a write-plan array the same way it does in any JSON body: the directive object’s own keys are the per-row template (see row expansion). {{$writeback.recordId}}, {{$writeback.updates}}, {{$writeback.adds}}, and {{$writeback.removes}} come from the record source configured above; {{$item.lineId}} is the connector line id carried on each matched or removed row.
Ingestly derives the request from op / entity / id because the connector and entity are already configured on the node, so it can build the navigation path correctly every time. For a request this can’t express, use the HTTP action node instead.
Business Central applies the whole operations document as a single transactional $batch request: every operation succeeds, or none do.
Use {{$writeback.*}}, not {{writeback.*}}. There is no reserved bare writeback head: an unprefixed reference is an ordinary node reference and fails if no node named writeback exists upstream. The $ prefix is what lets a workflow also have a node named writeback with no ambiguity.

Post purchase invoice

Use this operation after a Purchase invoice Reconcile whose purchase order source is a Business Central Look up. Choose the Matched invoice result. The node inherits the purchase order, vendor invoice number, proposed quantities, connection, company and review policy from that match. You do not configure an entity, a body or individual quantity updates. Leave Document date blank to keep the purchase order’s document date, or point it at the invoice date field; it sets the Business Central document date and recalculates payment dates. Leave Posting date blank to use Business Central’s default posting date. When price checks are off in Reconcile, Business Central’s own prices apply.
Posting requires the Ingestly Connector extension in the selected Business Central environment. In that company, open Ingestly Connector Setup and turn on Enabled under Purchase posting. Enable it in your sandbox first to test your configuration. The capability status beside the matched invoice tells you whether posting is enabled; if it is not, the node stops before writing anything.
Assign Ingestly Connector Setup (ING PURCH ADMIN) to the administrator who manages the setup page, and Ingestly Purchase Posting (ING PURCH POST) to the Microsoft Entra application behind the connector, together with the usual Business Central permissions to read and post purchases. Scope each assignment to the intended company. Enablement is per company: turn it on in every company you post from, and check it again after the extension is installed or updated. After changing the setup, refresh the capability status in Ingestly. The operation posts one positive invoice against one purchase order using the receiving mode Reconcile chose: Receive and invoice receives what is not yet received and invoices the matched quantity, Use existing receipts invoices received quantities only. It accounts for quantities already received and leaves omitted purchase order lines untouched. If the purchase order changed since the match, it rechecks the proposal; with Review differences on in Reconcile a new problem opens a review task on the posting step, otherwise the step stops.

Configurations the operation refuses

Supported today: Item, G/L Account and Item Charge lines, partial invoices, quantities already received but not yet invoiced, and approved extra lines. Everything below is checked before any write and refuses the whole post rather than posting part of the order. Handle those orders in Business Central. Receiving more than was ordered needs an over-receipt allowance in Reconcile and an Over-Receipt Code on the line whose tolerance permits the excess; the smaller of the two limits applies. Preview and Test Step do not post. A successful run returns the posted invoice, its receipts, the operation ID and the posting time; receipts are empty when existing receipts covered the invoice. The output also carries the purchase order after posting (order) with its status (open or closed), a link while it stays open and, when Archive Orders is on in Purchases & Payables Setup, the archived version (order.archive). If Business Central does not confirm an attempted post, the step reports Recovery required. A retry checks the saved operation before posting anything further; it never blindly sends the invoice again. Do not create a second invoice to work around an unresolved posting result. To build the complete flow, pick Post a purchase invoice against a purchase order in the workflow templates. Choose the connection, partial-invoice policy and reviewer, then inspect the preview. Applying the template replaces the canvas in one undoable edit.

Confirm purchase order

Applies the amendment an Order confirmation Reconcile prepared: confirmed quantities and prices within tolerance, expected receipt dates and the vendor order number are written to the purchase order in one transaction. The node reads everything from the Matched confirmation; the purchase order, its company and the connection come from the lookup that Reconcile compared against.
This operation needs the Ingestly Connector extension in Business Central with Enable purchase order amendments turned on, and the Ingestly Purchase Amendment permission set assigned to the connector’s application. The operation selector shows Purchase order confirmations are supported once both are in place. See Connectors.
Before writing, Ingestly refreshes the purchase order and checks the match again. If the purchase order changed since the review, or Business Central refuses the change (a quantity below what has been received, a price on an invoiced line), the run opens a new review round instead of writing. A missing extension or permission fails the step. A confirmation that matched the purchase order exactly still runs the operation and reports no changes applied, so the run record shows the confirmation was checked. A preview or a test run never writes: the step stops before the amendment and reports that confirming a purchase order is unavailable in preview and single-step tests.

Duplicate check

Applies when Operation is Insert; the panel is not available in Update, and a lookup has nothing to guard. An Update writes to a record that already exists, so a lost response can’t be resolved by looking the record up the same way a lost create can; it fails the step rather than risk a wrong resolution.
Turn on Duplicate check to identify the record this step creates by its natural key. Before every write, Ingestly looks that key up in Business Central and fails the step without writing when a matching record already exists, so running the same document twice, or restarting a workflow, cannot create a second record. Leave it off and nothing at the destination is checked.
  • Entity: defaults to the node’s configured entity.
  • Keys: one or more field/value pairs that identify the record by its natural key, for example Field: externalDocumentNumber, Value: {{extract.payload.invoiceNumber}}.
A blocked write fails the step with a message naming the entity, the key values, and the existing record’s document number, for example The destination already has purchaseInvoices with vendorInvoiceNumber I-99576 (number 107378). Nothing was sent. The run’s callback history records it as skipped rather than delivered. If the lookup itself fails, the step fails without sending and is retried under the node’s retry policy; it never falls back to a blind write. The same lookup also covers a lost response: if the connection drops after Business Central accepts the write but before Ingestly sees the answer, the retry finds the record and reuses it instead of creating a second one. Without a duplicate check an unresolved attempt like that fails instead of guessing.

Body template

The body auto-generates from the entity, operation, and the columns carried into this step, using the same scaffolds as the Business Central guide’s deep insert. Edit the body directly and your changes are preserved: the scaffold only regenerates while the body is still exactly what it last generated, so a hand-edited body is never overwritten. Use the Generate body action to reset a body back to a fresh scaffold.

Advanced

The Advanced section exposes the raw body template editor (with autocomplete and validation) and the header editor. JSON bodies support row expansion with $each, $when, and $case.

Inputs and outputs

Allowed inputs: any trigger, and any action node that produces a result payload (extract, validation, transform, filter, split, classify, merge, parse, review, wait, if, switch, loop, variable, store, prompt, reconcile, HTTP, call workflow, Business Central, QuickBooks, callback). A Business Central node can feed a Business Central node: write the invoice, then read the record back. Output: An Insert or Update sends the request to Business Central and makes the response available to later steps. Request-level fields land under metadata.businessCentral (statusCode, method, url, attempts, requestSucceeded). A following step is optional: the node can end a branch, or feed the steps after it. A Look up hands the matched record (or the array of them) down as payload, with the outcome under metadata.businessCentral (found, matchCount, truncated, statusCode). It leaves through its Found or Not found port rather than a plain output (see When nothing matches), so every following step hangs off one of the two. A lookup costs 0 credits, and a dry run does not skip it: the query reaches your live tenant. It reads a record; it does not read the document.

Using the result downstream

After an Insert or Update, the node’s response is available to later steps. A JSON write returns the created or updated record, so {{NodeName.payload.id}} is the new record’s id. An OData $batch write instead returns {{NodeName.payload.responses}}, one entry per operation, each carrying id, status, headers and body, so the first operation’s new id is {{NodeName.payload.responses[0].body.id}}. After a Confirm Purchase Order, payload describes what was written: purchaseOrderId and purchaseOrderNumber, changeCount and noChanges, reopened (whether a released order was reopened and released again), purchaseOrderVersionBefore and purchaseOrderVersionAfter, vendorOrderNumber (from and to) when it changed, one entry per changed line under lines with quantity, netUnitPrice and expectedReceiptDate changes (each from and to), and appliedOn. After a Look up, payload is the connector record itself, with no wrapper around it, so a downstream reference names the Business Central field directly:
Ingestly does not know the shape of a Business Central record, so autocomplete stops at payload. The fields under it still resolve at run time; they are simply not offered as suggestions. Use Select to make it obvious which fields a step is meant to be reading.
metadata.businessCentral carries the request and the outcome: An Update with nothing to send (the reconcile found no changes) makes no request at all. The step succeeds with a null payload, statusCode 204 and method NONE.
The node sits in the Actions group of the node picker. In Insert, Update or Confirm Purchase Order it behaves as an output: a following step is optional, it cannot be disabled, and Test Step is not offered because a test would write to your live tenant. In Look up a following step is required, the node may be disabled, and Test Step runs the real query. Test Step is also refused on any node below an Insert, Update or Confirm Purchase Order, since a test run executes every step above the one being tested.

Error output

Turn on Error output in the node’s settings to add an Error port beside the node’s other ports. When the write fails after its retries, or a lookup fails, the run follows that port instead of failing, so you can route the failure to a Review, a notification, or a compensating step. With no error edge drawn, a failed step fails the run exactly as before. A no-match takes this port only when Fail if not found is on. With the option off, no matches are a successful lookup and take Not found.
Inside a loop body the Error output toggle is not offered and the error port never renders. Whether a failing item stops the loop is the loop’s own If an item fails setting instead. See Routing failures.

Business Central guide

Connector setup, deep insert, and multi-entity batch requests

Reconcile

Compare the looked-up record against the document

QuickBooks

The Look up, Insert and Update operations against QuickBooks Online

Connectors

Set up a Business Central connector

Order confirmation

Prepare the amendment this node applies