Outbound integration is how xMatix sends its records to another system: an administrator builds a flow on an integration app, points its last step at a connection, and starts it with a trigger — on every record change, on a schedule, or by hand. It comes after you have connected the external system (app, secret, connection, binding) and before you watch the runs on the app's Overview and Errors pages.
Overview
There are three ways to send data out, and choosing between them is most of the design work:
| Shape | Starts when | Fits |
|---|---|---|
| Entity-event flow | A record of one entity is created, updated or deleted | "Tell the other system the moment an order changes" |
| Scheduled flow | A cron schedule falls due | Nightly exports, hourly batch uploads, targets that prefer many records per call |
| Outbound sync profile | The profile's schedule runs | "That system should keep reflecting these entities", with change tracking, record pairing and conflict handling done for you |
xMatix has no self-service subscription list where a third party registers its own callback address. Every outbound call is a flow an administrator configured, against a connection the integration app holds. (Inbound webhooks are a separate feature: Webhook triggers accept calls into xMatix.)
When to use it
- Entity-event flow — when the other system must hear about individual changes within seconds, and one call per change is acceptable.
- Scheduled flow — when the target wants feeds rather than events, rate-limits per call, or only needs the data once a day or once an hour.
- Outbound sync profile — when you need a standing contract: only changed records each cycle, the external id remembered for each record, no echo loops, and conflicts surfaced when both sides edited. See Scheduled sync.
How xMatix handles it
Entity-event triggers
An Entity Event (record change) trigger names one entity and one or more of the events Create (record created), Update (record changed) and Delete (record removed). After a save of that entity commits, xMatix checks the app's active Entity Event triggers and starts each matching flow.
- The save comes first. The trigger is evaluated after the record is saved, and the flow runs in the background. A trigger or flow failure never undoes the save and never shows the user an error.
- The trigger hands over only the record's identity:
{ "entity": …, "op": "Create" | "Update" | "Delete", "id": … }. It does not carry the record's fields. To send current values, start the flow with a Read entity step whose Filter (Dynamic LINQ) isId == "${trigger:id}". - An optional filter narrows the trigger. Filter (optional) is a predicate on the record's fields, such as
Status == "Approved" && TotalAmount > 1000. xMatix re-reads the saved record with the filter and starts the flow only when it matches. If the filter cannot be evaluated or matches nothing, no run is started. - A filtered trigger never fires on Delete, because the deleted record can no longer be read. If you need deletes, use a separate trigger without a filter.
- Every save is its own run. Two quick edits to one record start two independent runs, and they are not guaranteed to finish in order. A duplicate notification for the same save is recognised and ignored.
- No loops from write-backs. Records written by a flow that an entity-event trigger started do not fire entity-event triggers again. Scheduled, webhook and manual runs are not suppressed: a scheduled import that writes Orders does fire an Order entity-event export. Design and test such chains so they end.
- Test traffic never goes out. Saves made by a test run do not start integration flows.
- The entity's Execution Plan shows them. Setup → Design Studio → Entities → the entity → Logic → Execution Plan lists the active Entity Event triggers by flow name, for example "Starts on Create, Update, when its filter matches." See What runs when you save a record.
Scheduled triggers
A Schedule (cron) trigger runs its flow when a six-field cron expression (seconds first) falls due — 0 */15 * * * * is every 15 minutes, 0 0 2 * * * is 02:00 every day. Schedules are evaluated in UTC. Open schedule editor builds the expression for you.
- If several occurrences were missed (for example while the app was inactive), the trigger fires once for the latest one, not once per missed slot.
- While the same flow still has a run in progress, the next occurrence waits and fires once that run ends, so two runs of one scheduled flow do not overlap.
- Schedules are skipped while the app is inactive. They can also be held while your subscription is locked or read-only; the next slot after it is unlocked fires normally.
What a flow sends
An outbound flow is usually three steps: a source, a transform and a sink.
| Step | Use it for |
|---|---|
| Read entity | Read xMatix records through a binding — the triggering record (filter on ${trigger:id}) or every record in scope for a scheduled export |
| Map fields, Filter, Lookup, Script | Shape the payload the other system expects |
| Batch, For each | Split a collection into groups of N for bulk calls, or run the next step once per record |
| Connector write | Send the result through a connection |
With the HTTP REST connector the request body is JSON. If Body template (JSON) is empty, the step's input is sent as is. The call goes to the connection's url. To address one record (for example https://portal.example/api/orders/${input:orderNumber}), add a url key to the step's raw JSON: settings on the step override the same settings on the connection, and tokens are resolved in the address. HTTP REST does not read Path / resource. Batch-capable connectors such as Salesforce report a result for each record, so one bad record does not sink the whole batch.
Delivery, failures and retries
- Transport failures are retried automatically. When a run fails because of a network error or a timeout, xMatix retries it by default up to three attempts in total. It waits 30 seconds before the first retry and doubles the wait after that. Only failures from the last 24 hours are retried. When the attempts run out, the run becomes DeadLettered.
- Other failures wait for you. A failure that would fail the same way again — a mapping error, a missing secret, a flow that no longer compiles — stays Failed and is not retried.
- Inside one call, read requests are retried on 5xx, 408, 429 and network errors, honouring the partner's Retry-After. Write requests are not retried inside the call, so a write is never sent twice by the same attempt.
- A rejected HTTP write does not fail the run on its own. The Connector write step records the reply's status code and body as its output and the flow carries on. A run can therefore show Succeeded although the target answered 400 or 500. Check the step's output while you test, and turn on Capture step data on the flow so successful runs keep it too.
- Retries and replays use the flow's current active version, and its archived input. For an entity-event run, that input is only the record id, so a replay reads the record as it is now.
- Design the target for repeats. A run that timed out may have reached the other system before it was retried. Send a stable key and use upsert-style calls ("set this record to this state") rather than "create a new row per event".
When nothing is recorded
Some outbound attempts leave no run on the Overview page:
- the app's Active setting is off — every flow is refused with "Integration app is disabled. Re-enable the app to resume its flows.";
- the tenant is a sandbox and the app does not have Allow sandbox execution;
- an entity-event trigger fires for a flow that has no active version;
- an entity-event trigger's filter did not match the record, or the record was deleted and the trigger has a filter.
Prerequisites
- The Manage integrations capability, and the Admin role on the integration app (needed to build flows and triggers). See Integrations.
- A working connection to the target system, tested with Test Connection — see Connect an external system.
- An Outbound (or Bidirectional) binding on the entity you are sending.
- A Run as user on the app whose security profiles may read that entity. Flows and trigger filters read records as that user.
Procedure
Step 1 — Build the outbound flow
- Go to Setup → Platform → Integrations, open the app and go to Flows.
- Create the flow and open it in the designer.
- Add a Read entity step. Pick the Binding. For an entity-event flow, set Filter (Dynamic LINQ) to
Id == "${trigger:id}"; for a scheduled export, filter the records in scope (for example on a status or a modified date) and set Page size and Max pages (0 = unlimited). Fields to include keeps only the fields you list. - Add Map fields (and Batch if the target accepts several records per call).
- Add a Connector write step: Connector type (for example
http.rest), Connection, HTTP method (POST, PUT, PATCH or DELETE; POST by default), any Extra headers, and optionally a Body template (JSON) built from${input:field},${step:id.path},${trigger:id},${config:key}and${secret:name}. - While you test, turn on Capture step data so successful runs keep each step's input and output.
- Preview the flow and activate the version. Only the active version runs.
Step 2 — Add the trigger
- On the app's Triggers page select New Trigger.
- Pick the Flow and the Trigger Type:
- Entity Event (record change) — choose the Entity, tick at least one of the Events, and optionally enter a Filter (optional).
- Schedule (cron) — enter the Schedule (cron expression) in six-field form, or use Open schedule editor.
- Leave Active on and select Create. The trigger appears in the list with Status Active.
Step 3 — Test it
- In the trigger's row select Fire now. For an Entity Event trigger the payload is pre-filled with the entity and
"op": "Update"; type the id of a test record and select Fire now. Each click starts a new run. - Open the app's Overview and check that the run reached Succeeded.
- Select Step data on the run and check the Connector write output: the status code must be a 2xx. Then check the record in the other system.
- For an Entity Event trigger, also edit a test record in xMatix and confirm that a new run appears within seconds.
If the dialog shows "Run refused: …", the run was refused before it started — usually because the app is inactive or a sandbox has not been allowed to call out.
Step 4 — Pause, change or remove the trigger
- Pause in the trigger's row stops it without losing its settings; Activate turns it back on. A paused Entity Event trigger ignores saves made while it was paused — they are not sent later.
- Edit changes the type, schedule, events or filter. The flow cannot be changed on an existing trigger; create a new trigger instead.
- Delete removes the trigger after confirmation.
- To stop every flow of the app at once, turn the app's Active setting off.
Step 5 — Replay or cancel a run
- On the app's Overview or Errors page, find the run.
- For a run that is Failed, Succeeded, DeadLettered or Rejected, select Replay. Leave the payload empty to reuse the run's archived input, or enter a JSON payload to override it, add a reason and select Replay. A new run starts, linked to the original; its Attempt is one higher.
- For a run that is Pending, Running or PendingApproval, select Cancel run. The run is marked Failed with an OperatorCancel error. Work already in progress on the server is not interrupted.
Fields
New Trigger dialog
| Field | What it means | Notes |
|---|---|---|
| Flow | The flow this trigger starts | Required. Cannot be changed after the trigger is created |
| Trigger Type | What starts the flow | Schedule (cron), Poll (cron-driven connector read), Webhook (inbound HTTP), Entity Event (record change), Data Lake Event, Manual (user-initiated). Outbound flows normally use Entity Event or Schedule |
| Schedule (cron expression) | When a Schedule or Poll trigger fires | Required for those types. Six fields with seconds first; evaluated in UTC |
| Entity | The entity whose saves start the flow | Entity Event only. Required |
| Events | Which operations start it | Entity Event only. Create, Update, Delete; at least one |
| Filter (optional) | A predicate the saved record must match | Entity Event only. Checked after the save; a filtered trigger never fires on Delete |
| Active | Whether the trigger fires | On by default. Shown as Active or Paused in the list |
Read entity step
| Field | What it means | Notes |
|---|---|---|
| Binding | The entity (and view) to read | Required. Set the entity and view on the binding, not here |
| Page size | Records per page | Default 200, up to 5000 |
| Max pages (0 = unlimited) | Stop after this many pages | Default 0 |
| Order by | Sort order | For example UpdatedDateTime desc |
| Filter (Dynamic LINQ) | Which records to read | Id == "${trigger:id}" reads the record that fired the run |
| Fields to include | Comma-separated field names to keep | Blank keeps all fields |
Connector write step
| Field | What it means | Notes |
|---|---|---|
| Connector type | The connector of the connection | Default http.rest; must match the connection's connector |
| Connection | The connection to send through | Required |
| HTTP method | POST, PUT, PATCH or DELETE | Default POST |
| Path / resource | The file path or object to write to | Read by connectors that address a file or object, such as Azure Blob; HTTP REST ignores it and calls the connection's url |
| Extra headers | Additional request headers | May use ${secret:name} |
| Body template (JSON) | The body to send | Blank sends the step input as is |
Business rules
- Entity-event triggers fire only after a successful save, in the background; their failures never affect the save.
- A trigger with no events selected in stored configuration fires on all three operations; the dialog requires at least one.
- Records written by an entity-event-started run do not fire entity-event triggers again; other run types are not suppressed.
- Each save starts its own run; a repeated notification of the same save is ignored as a duplicate.
- Scheduled triggers fire once for the latest missed occurrence and wait while the same flow is still running.
- By default, transport failures are retried up to three attempts in total with a doubling wait from 30 seconds, then dead-lettered; other failures stay Failed.
- A manual replay of a failed run stops that run from being retried automatically.
- Replays and retries run the flow's current active version. A replay is refused when the original flow version was deleted, or when there is neither a payload nor archived input.
- Firing a paused trigger is refused with "Trigger is paused (IsActive=false). Activate it before firing."
Example
A distributor keeps its delivery partner's portal up to date with approved orders.
- The administrator opens the "Delivery portal" integration app, whose Run as user may read Orders, and adds an Outbound binding on Order.
- They build a flow: Read entity on the Order binding with
Id == "${trigger:id}", Map fields to the portal's order shape (order number, customer, delivery address, lines), and Connector write through the portal's HTTP REST connection with HTTP method PUT and, in the step's raw JSON, aurlending inorders/${input:orderNumber}, so a repeat send updates the same order instead of creating a second one. - They add an Entity Event (record change) trigger on Order with Events Create and Update, and Filter (optional)
Status == "Approved". - Using Fire now with a test order's id, they confirm the run is Succeeded and the step output shows status 200.
- The next morning a sales manager approves order SO-1042 at 09:12. Within seconds a run appears on the app's Overview and the portal shows the order. Draft orders saved earlier that day started no runs, because they did not match the filter.
Training
Practice exercise
In a sandbox app that has Allow sandbox execution on and an HTTP REST connection to a test endpoint, build a flow that reads one Item by ${trigger:id} and writes it with Connector write. Add an Entity Event (record change) trigger on Item with Events Update only, turn on Capture step data, then edit any item's description.
Expected result: a new run appears on Overview within seconds and reaches Succeeded; its Step data shows the item's fields in the Read entity output and the endpoint's status code in the Connector write output. Creating a new item starts no run.
Quick reference
- Push on change: Entity Event (record change) trigger. Push on a cadence: Schedule (cron) trigger. Standing contract: an outbound sync profile.
- The trigger passes only
entity,opandid— read the record withId == "${trigger:id}". - Filtered triggers never fire on Delete.
- Cron has six fields with seconds first and runs in UTC.
- An HTTP error reply does not fail the run — check Step data.
- Use PUT or upsert with a stable key so repeats are harmless.
- Replay for finished runs, Cancel run for unfinished ones; both need the Operator role.
- App Active off stops every outbound flow of the app.
Permissions
| Task | Needs |
|---|---|
| See the integration screens | The Manage integrations capability on your security profile |
| See runs, errors and triggers of an app | The Viewer role on the app |
| Replay or cancel a run | The Operator role |
| Create, edit, pause, delete or Fire now a trigger; build and activate flows | The Admin role |
What the flow itself can read is decided by the app's Run as user, not by the person who built it. If that user's profiles cannot read the triggering record, a filtered trigger finds no match and starts no run, and a Read entity step returns nothing. See Integrations for the roles.
Configuration
| Setting | Where | What changing it affects |
|---|---|---|
| Trigger type, schedule, events and filter | The app's Triggers page → New Trigger / Edit | When the outbound flow starts and for which records |
| Trigger Active | Pause / Activate in the trigger's row | Stops or resumes one trigger |
| Capture step data | The flow designer | Whether successful runs keep each step's input and output (failed runs always do) |
| Run as user | The app's Edit dialog | Which records the flow and trigger filters can read |
| App Active | The app's Edit dialog | Refuses every flow of the app while off |
| Allow sandbox execution | The app's Edit dialog, in a sandbox | Whether a sandbox may call the target system |
| Delete propagation | A sync profile's entity declaration | None — deletes are not propagated (safest) is the default; Soft delete; Hard delete — physical, needs approval. See Scheduled sync |
Common problems
Records change but no run appears
Check, in order: the trigger shows Active; the app is active; the flow has an active version; the trigger's Entity and Events match what you did (a new record is Create, not Update); the record matches the Filter; and the app's Run as user can read the record. None of these cases leaves a run behind, so the Overview page stays empty. The entity's Execution Plan shows whether the trigger is seen at all.
Deleting a record does not notify the other system
The trigger has a Filter. Filtered triggers cannot evaluate a deleted record and never fire on Delete. Add a second Entity Event trigger with Events Delete and no filter.
The run is Succeeded but the other system has nothing
The target probably rejected the call. A Connector write that gets a 4xx or 5xx reply records it as the step's output without failing the run. Open Step data, read the status and reply body, fix the mapping or path, and Replay the run.
The same record arrives twice
Two saves started two runs, or a run that timed out was retried after the target had already accepted it. Make the write idempotent: PUT or upsert by a stable key such as the document number.
Replay says "Replay requires a request body or an archived InputJson on the original run."
The original run has no stored input. Enter the payload in the Replay dialog — for an entity-event flow, { "entity": "…", "op": "Update", "id": "…" }.
Replay says the original flow version no longer exists
The version the run used was deleted. Fire the trigger again with Fire now instead.
"Run refused: Integration app is disabled. Re-enable the app to resume its flows."
The app's Active setting is off. Edit the app and turn it on; nothing that was refused while it was off is sent later.
Common questions
Can an external system be told the instant something changes in xMatix?
Yes. An Entity Event trigger starts the flow in the background right after the save commits, usually within seconds, and delivers through whatever connection the flow uses. What xMatix does not offer is a self-service subscription list where the external party registers its own address: the notification is a flow an administrator configured inside an integration app. That is a governance difference, not a speed difference — every target is a reviewed connection with its credentials kept in the app's secrets.
Can xMatix POST to an arbitrary URL?
Yes. The HTTP REST connector sends a JSON body to the connection's url (or a url set on the step), with any headers you configure, including credentials taken from the app's secrets through ${secret:name}. Use it as the Connector write step of an entity-event or scheduled flow. The address belongs to the connection, so changing where data goes is a reviewed configuration change on the integration app, not something a flow author can redirect silently.
What happens when the target system is down?
The xMatix record is already saved, so nothing is lost on the xMatix side. A connection failure or timeout fails the run, and by default xMatix retries it twice more with a growing wait before marking it DeadLettered. Once the target is back, open the app's Errors page and Replay the dead-lettered runs; an entity-event replay reads the record as it is now. A sync profile instead picks up from the last change it delivered on its next cycle.
Should I push deletes?
Cautiously. Entity Event triggers can fire on Delete (when they have no filter), and sync profiles offer Delete propagation, but the sync default is None, because a wrong delete is the one mistake the other system cannot undo. Prefer status fields such as Cancelled or Inactive, which travel as ordinary updates, and reserve real delete propagation for pairs of systems where you have planned recovery. A delete event carries only the record id, because the record is no longer readable.
Does an outbound flow slow down saving records?
The save does not wait for the flow. After the save, xMatix only looks up matching triggers and hands the work to the background; the flow, including any call to the other system, runs separately. A slow or failing target therefore never delays or blocks the user who saved the record.
