> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ingestly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Callback

> Send pipeline results to an external webhook URL.

The callback node sends pipeline results to an external URL via an HTTP request. It is a terminal node: no action node runs after it. The one exception is another callback, which can chain after it to reuse its response (see [Chaining callbacks](#chaining-callbacks)). Use callbacks to integrate Ingestly with your backend systems, databases, or third-party services.

## Configuration

| Field                 | Type             | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| --------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **URL**               | string           | Yes      | The webhook URL to receive the results                                                                                                                                                                                                                                                                                                                                                                                                      |
| **Method**            | select           | No       | HTTP method: `POST` (default), `PUT`, or `PATCH`                                                                                                                                                                                                                                                                                                                                                                                            |
| **Headers**           | key-value editor | No       | Custom headers to include in the request                                                                                                                                                                                                                                                                                                                                                                                                    |
| **Body**              | template editor  | No       | Custom body template. Defaults to the full pipeline output. JSON bodies support [row expansion with `$each` and `$when`](/guides/expressions#row-expansion-in-json-bodies-each-and-when)                                                                                                                                                                                                                                                    |
| **Body format**       | select           | No       | `JSON` (default) sends the body as `application/json`. `OData Batch` sends a Business Central JSON `$batch` request with `Isolation: snapshot` and supports the `{{reconcileWriteback}}` token (see below); it requires a Business Central connector (see the [Business Central guide](/guides/business-central)). `Binary (base64)` sends the resolved body, which must be a Base64 string, as raw bytes (see [Binary body](#binary-body)) |
| **Timeout (seconds)** | number           | No       | Request timeout in seconds. The send is cancelled after this many seconds. Leave blank to use the system default (45s)                                                                                                                                                                                                                                                                                                                      |

<Note>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).</Note>

## Creating records from a reconcile result

With the `JSON` body format, click **Generate from reconcile** above the body editor to insert a starter body. The scaffold contains a header field and one `$each` row template per reconcile **Expected extras** label, plus a default template for unlabeled rows. Rename the example fields to your connector's field names and the body posts the reconciled lines as one create request.

## Write-back with {{reconcileWriteback}}

With the `OData Batch` body format, the body can embed the `{{reconcileWriteback}}` token. At run time the token expands into the batch operations that write the approved reconcile values back to the connector record (changed fields are updated, classified extra lines are added). Click **Insert write-back** above the body editor to insert the minimal body:

```json theme={null}
{
  "operations": "{{reconcileWriteback}}"
}
```

The token can also sit inside the `operations` array next to static operations you author yourself; the generated operations are spliced in at the token's position.

When the body contains the token, the write-back panel appears with the following fields:

| Field                     | Type            | Required                                 | Description                                                                                                                                                             |
| ------------------------- | --------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Reconcile node**        | select          | Yes                                      | The upstream reconcile step whose approved values are written back. You need a reconcile node upstream, or this selector is empty                                       |
| **Entity**                | string          | Yes                                      | The Business Central entity collection the write-back targets, such as `salesOrders`. Required because the `/$batch` URL does not name the entity                       |
| **Record id path**        | template editor | Yes                                      | The path to the record's unique id, read at run time to target the update. For example, use `{{value[0].id}}` for a collection response or `{{id}}` for a single record |
| **Write back line items** | toggle          | No                                       | When on, reveals a required **Line id path** field                                                                                                                      |
| **Line id path**          | template editor | Yes when **Write back line items** is on | Points at each line's id, for example `{{id}}`                                                                                                                          |

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 (an empty write set) and the body has no static operations, the step succeeds without sending a request

<Note>
  The `Connector Write-back` and `Create record` body formats still run on pipelines that were saved with them, and they appear in the format picker marked **(legacy)** on those nodes. New pipelines use the `JSON` and `OData Batch` formats described above.
</Note>

## Binary body

Set **Body format** to `Binary (base64)` to send the request body as raw bytes instead of JSON. The body template must resolve to a Base64 string, typically exactly `{{$document.file.base64}}` (the [source document](/guides/expressions#source-document-file)).

* Ingestly decodes the Base64 string and sends the resulting bytes as the request body.
* The content type defaults to `application/octet-stream`. Set a `Content-Type` header to override it.
* `GET` and `DELETE` requests never send a body.
* If the resolved body is not valid Base64, the step fails with a clear error instead of sending malformed bytes.

The raw bytes and the Base64 text are never persisted: the request history records a binary body as `[binary N bytes, type]`.

A binary body is how you upload a file to a system that expects raw bytes, such as the Business Central `attachmentContent` endpoint. See the [attachment recipe](/guides/business-central#5-attach-the-source-document-to-a-record).

## Chaining callbacks

A callback is terminal for action nodes, but you can connect one callback to **another callback**. The downstream callback runs after the first one returns and can reference its response. This is how you use a value that only exists after the first call completes, such as the id of a record the first callback created.

Reference the previous callback's response through its node name, using the same [path syntax](/guides/expressions#path) as any upstream node:

* A callback's `payload` **is the response body**. Request-level fields such as the status code ride under `metadata.callback`.
* For a plain JSON response, read a field directly: `{{<callbackName>.payload.id}}`.
* For an `OData Batch` response, the body is a `responses` array with one entry per operation, each shaped `{ id, status, headers, body }`, where `id` echoes the operation's `contentId` and `body` is that operation's result. Index into it: `{{<callbackName>.payload.responses[0].body.id}}`.

<Tip>Give the record-creating batch operation a `contentId` so you can tell which `responses` entry is the one you want.</Tip>

## Dry run behavior

On a [Dry run](/guides/test-mode), the callback node does not send the HTTP request.

Instead, the run output shows a preview with:

* The resolved request URL
* The resolved request headers
* The rendered request body

For a `Connector Write-back` callback, the dry-run preview shows the prepared request that would be sent, rendered in a read-only JSON editor.

<Tip>Use a dry run to verify callback templates before you send live outputs.</Tip>

## Inputs and outputs

**Allowed inputs:** Any action node that produces a result payload (extract, review, validation, transform, merge, parse, HTTP, loop, variable, store, prompt), and another callback node (see [Chaining callbacks](#chaining-callbacks)). Filter and split are not among them: they emit page groups, not a result to send, so put the node that produces the data between them and the callback.

**Output:** Sends an HTTP request to the configured URL with the pipeline results. The node is terminal for action nodes, but its response can feed one more callback.

## Related

<CardGroup cols={2}>
  <Card title="Webhooks and callbacks guide" icon="book" href="/guides/webhooks-and-callbacks">
    Payload format, verification, and integration patterns
  </Card>

  <Card title="Webhook signing keys" icon="key" href="/admin/webhook-signing-keys">
    Verify webhook signatures for security
  </Card>

  <Card title="Email output" icon="paper-plane" href="/nodes/email-output">
    Deliver results via email instead
  </Card>

  <Card title="Transform action" icon="arrows-rotate" href="/nodes/transform">
    Transform data before sending via webhook
  </Card>

  <Card title="Business Central guide" icon="building" href="/guides/business-central">
    Connector write-back and OData batch requests
  </Card>
</CardGroup>
