Appearance
Integration Flows reference
This page covers the screens that build, release, run and repair integration flows: Integration Flows (with the visual designer), Templates, Mappings, Lookup Tables, Integrations (the governed release path), Events, Failed Items, Approvals and Waiting Runs, Go-Live Approvals and Trace an Event. They are used by integration developers, release approvers and operators. Terms such as connection, trigger and correlation id are defined in the Overview.
A flow is stored as JSON in the definition of a flow record. Every example in this page uses the real step vocabulary of the flow engine and is accepted by its validator.
Integration Flows
The list shows every flow with its monitoring counters, lets an operator run, switch on or off, delete and inspect flows, and opens the visual designer. The designer is where flows are built.
Where to find it
Studio Explorer > Workspace > Integrations > Integration Flows (page key integration-flows). The designer opens from New flow in the designer or Design on a row (page key integration-flow-designer). Start from a template opens Templates.
Key concepts
| Term | Meaning |
|---|---|
| Flow code | Unique identifier of the flow in the tenant. Fixed after creation. |
| Step | One unit of work with a code unique in the flow. |
| Dependency wave | Steps are run in waves. A step with no dependsOn key depends on the step before it in the array. "dependsOn": [] makes a root that runs in the first wave in parallel with other roots. "dependsOn": ["a","b"] is a join. Steps of one wave run concurrently. |
| Trigger | What starts a run: manual or API, a business event (with an optional filter), a schedule (cron) or an inbound web address (webhook). |
| Run (execution) | One execution of a flow with a status, input, context and per-step records. |
| Saga compensation | An optional reverse call on a step. When a later step permanently fails, the reverse calls of already-succeeded steps run in reverse order. |
List screen
Chips above the grid: Total, Running, Queued, Success, Failed, Dead, Avg duration, Failure rate (both a dash until a run has completed) and a Workers chip (Workers: active/core (max N), redis up|down, shown to callers who may manage).
| Column | Content |
|---|---|
| Integration Flow | Name and code. |
| Plugin | Owning plugin id, studio for flows made by hand. |
| Version | vN. |
| Schedule | Cron expression or a dash. |
| Trigger event | Event type or a dash. |
| Status | ACTIVE or DISABLED. |
Row actions: Execute now (enabled for ACTIVE flows only), Design, Activate or Disable, Delete. Selecting a row opens the history drawer (20 runs per page, columns Started, Trigger, Status, Duration). Selecting a run opens the step detail: for each step the code, status (SUCCESS, SKIPPED, FAILED...), type, attempt, duration, HTTP status and error. For FAILED or DEAD runs AI: Analyze failure produces a plain-language summary ("AI analysis unavailable (no API key configured)." when no model is set up). Sensitive fields in step requests and responses are masked.
Tabs: Integration Flows, Connections (a short form for REST connections; use Connections for everything else) and Dead Letter Queue (DEAD runs with a Retry from scratch action).
New Integration Flow dialog (JSON editor)
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Prompt and AI Generate | text | empty | No | Describes the flow in words, for example "Create an employee, then create their user account". The result fills the code, name and definition. It is a draft only. |
| Integration Flow Code | text | empty | Yes | |
| Name | text | empty | Yes | |
| Description | text | empty | No | |
| Definition (steps JSON) | JSON | one GET step | Yes | The object with a steps array. |
Save runs the engine validator first. Validation errors are listed in the dialog, one per line (see the troubleshooting table).
Run statuses
| Status | Meaning | Next |
|---|---|---|
QUEUED | Waiting for a worker. | RUNNING, CANCELLED |
RUNNING | A worker is executing steps. | SUCCESS, FAILED, WAITING, CANCELLED |
WAITING | Paused at a wait, a date, an event or an approval. Holds no worker. | QUEUED when the wait ends, CANCELLED |
SUCCESS | All steps succeeded or were skipped. | |
FAILED | A step failed permanently. Remaining unrelated steps stop; compensations run. | Resume, Retry |
DEAD | The run could not be completed at all: the flow definition is gone or unreadable, or a worker crashed and the run made no progress for the stale threshold (default 600 seconds). | Resume, Retry |
CANCELLED | Cancelled by a person. | Resume |
Step statuses: SUCCESS, FAILED, SKIPPED (a condition was false or an upstream step failed), TIMEOUT, WAITING. Trigger types recorded on a run include API, APP, EVENT, SCHEDULE, WEBHOOK and TEST.
Resume re-runs only the steps that never succeeded, in place, keeping the run id. Retry creates a new run from scratch with the same input. Cancel is available for QUEUED, RUNNING and WAITING runs.
Step reference
A step is a JSON object. type defaults to REST and is upper-cased.
| Field | Applies to | Default | Description |
|---|---|---|---|
code | all | none, required | Unique within the flow. Later steps read the result as ${steps.CODE.response}. |
type | all | REST | REST, MAP, APP, FLOW, DELAY, WAIT_UNTIL, WAIT_EVENT, WAIT_APPROVAL, FOREACH, LOOP, BATCH. |
method | REST | none, required | HTTP method. The designer offers GET, POST, PUT, PATCH, DELETE. |
url | REST | none | Full address, or a path appended to the connection's address. One of url or connectionCode is required. |
connectionCode | REST | none | The connection to call through. |
headers | REST | {} | Map of header name to value. |
body | REST | none | Any JSON, with ${...} placeholders. |
successStatusCodes | REST | 200, 201, 202, 204 | Statuses counted as success. |
timeoutSeconds | REST | 30 | |
retry | REST | none | {enabled, maxAttempts, backoff, initialDelaySeconds, maxDelaySeconds}. backoff is NONE, FIXED, LINEAR or EXPONENTIAL (delay doubles per attempt, capped by maxDelaySeconds). |
dependsOn | all | previous step | See dependency wave. |
runAfter | all | SUCCESS, SKIPPED | List of SUCCESS, FAILED, SKIPPED: which outcomes of the upstream steps allow this step to run. Any other value fails validation. |
condition | all | none | Boolean expression evaluated on the run context. False skips the step without failing the run. |
forEach, batchSize | LOOP, BATCH, FOREACH, FLOW | none, 1 | The list to go through. LOOP runs sequentially; BATCH runs batchSize items at a time. Inside, ${item} and ${index} are bound. |
steps | FOREACH | none | Inner steps, at least one. |
compensate | REST | none | {method, url, connectionCode, headers, body} reverse call. |
circuitBreakerThreshold, circuitBreakerCooldownSeconds | REST | 0 (never), 60 in the designer | Pause calls to the same target after that many failures, for the cooldown. |
rateLimitPerMinute | REST | 0 (no limit) | |
mappingCode or mapping, source | MAP | none | A saved mapping by code, or a mapping written inline, applied to source (for example ${input}). One of the two mappings is required. |
action, params | APP | none | A platform action. See the table below. |
flowCode | FLOW | none | Another flow to run. It must be switched on. |
delaySeconds | DELAY | none | 1 second to 30 days. |
params.until, params.timezone | WAIT_UNTIL | none | Date and time, or a placeholder; time zone defaults to UTC. At most one year ahead. |
params.eventType, params.match, params.timeoutSeconds, params.onTimeout | WAIT_EVENT | none | Event kind, up to 10 field=value conditions, give-up time 1 second to 90 days, FAIL or CONTINUE. |
params.title, details, timeoutSeconds, onTimeout, stopIfRejected, assignees | WAIT_APPROVAL | none | See Approvals and Waiting Runs. |
Engine limits: a list may hold at most 500 items; loops nest at most 3 levels; flows call each other at most 5 levels deep and never themselves; a delay longer than 300 seconds suspends the run instead of holding a worker; a wait cannot sit inside a loop except a delay of at most 300 seconds.
Platform actions (APP steps)
| Action | Parameters | Effect |
|---|---|---|
entity.create | entity, values | Creates a record. |
entity.get | entity, id | Reads one record. |
entity.update | entity, id, values | Updates one record. |
entity.delete | entity, id | Soft-deletes one record. |
entity.find | entity, optional filterField, filterValue, limit (up to 5000) | Result has count and items. The designer returns the first 200 when no limit is given. |
sftp.read | connection, path, optional encoding text or base64 | File content. Files are limited to 1 MB. |
sftp.write | connection, path, content, optional encoding | Writes a file. |
sftp.delete | connection, path | Deletes a file. |
sftp.list | connection, path (folder) | Files in the folder. |
db.query | connection, sql, params | One SELECT or WITH with :name placeholders; up to 5000 rows. Values are always bound, never concatenated. |
db.write | connection, sql, params | One INSERT, UPDATE or DELETE. |
queue.publish | queue, message, optional delaySeconds (0 to 2592000), dedupeKey | Puts a message on a queue. Up to 256 KB. |
file.parse | content, optional format csv, xml, xlsx or xls, name, encoding base64, delimiter, header (default true), sheet, record | Turns a file into rows. |
sync.run | sync, optional preview | Runs or previews a saved synchronization. A step test always previews. |
APP steps run inside the platform as the person or process that started the flow, so their permissions apply.
Visual designer
The designer is a canvas of cards. The toolbar shows the flow name, a chip vN - On|Off (or New), undo and redo, Save, Deploy, Test, Flow checker (with a problem count), Copilot and, for a live flow, Switch off. An unsaved live flow shows "Unsaved changes - this flow is on, saving changes it right away".
| Area | Content |
|---|---|
| Left panel tabs | Connectors (apps with ready actions), Actions (Call an API, For each item, Transform data, Condition, Run in parallel, Run another flow, Wait, Repeat for each item, SFTP, database, Queue, File rows, Sync), Outline, Versions (with a compare dialog). |
| Canvas | Trigger card, step cards, lanes for conditions (If yes, If no), parallel branches, loop bodies and "If it fails" paths. Zoom 40 to 150 percent, fit to width, mini-map. |
| Settings panel | Properties of the selected card. With nothing selected: flow Name and "What it does". |
| Step dock | Configuration, Request, Results, Logs for the selected card; a step can be tested alone. |
| Problems drawer | Problems found by the designer plus the server's checks. |
New flow dialog: Name and Code ("Used in addresses and logs. It cannot be changed later."). An existing code shows "A flow with this code already exists."
Deploy saves the flow and switches it on. If the flow requires go-live approval, switching on creates a request instead (see Go-Live Approvals). A flow whose definition the designer cannot represent opens read-only with its JSON; it still runs as written.
Trigger panel
| Field | Type | Default | Description |
|---|---|---|---|
| Starts | select | Started by hand or by API | Started by hand or by API; When a business event happens; On a schedule; When another system calls. |
| When a record of this kind / Starts when it | entity, created or changed or deleted | Writes the event kind entity.NAME.created, .updated or .deleted. The flow receives the record fields and an _event block with entity, record id and operation. Changes made by a flow's own actions do not start flows, so flows cannot loop. | |
| Or a ready-made event | select | None chosen | queue.message.received, sftp.ack.received, approval.requested, approval.decided, document.uploaded, sftp.file.arrived, poll.item.new, poll.item.updated. Each fills a sample. |
| Event kind | text | empty | Any event from the Events screen. |
| One of these fields changes | multi-select | any field | Updates only. Compiles to input._event.changed.FIELD == true. |
| Extra rule on the event data | expression | empty | Up to 2000 characters. On updates input._event.changed.FIELD and input._event.previous.FIELD are available. |
| Common schedules | select | Custom | Every 5 minutes 0 */5 * * * *; Every hour 0 0 * * * *; Every day at 9:00 0 0 9 * * *; Weekdays at 9:00 0 0 9 * * MON-FRI; Every Monday at 9:00 0 0 9 * * MON. |
| Schedule | cron | empty | Six fields: seconds minutes hours day month weekday, evaluated in UTC. |
| Address other systems call | read only | The flow's receiver address once the flow is saved. Add a secret or New secret generates a whsec_ signing secret, shown once ("Copy this now. It is not shown again."). | |
| Sample data | JSON | empty | An example of what the trigger delivers. Used for field lists and tests. Never sent anywhere. |
Card properties
| Card | Fields |
|---|---|
| All steps | Name, Note (optional). |
| Call an API / For each item | Method, Connection (or "None (full address below)"), Address or Path, Headers (one Name: value per line), Body (JSON). For each item also "List to go through" and "How many at the same time" (1 means one after another). Advanced: Give up after (seconds, default 30), Try up to (times; 0 or 1 no retry; retries wait longer each time), Counts as success (status codes), At most this many calls per minute (0 none), Pause after failures and Pause for (seconds, default 60). Only run if. Response mapping note. "If a later step fails, undo this with" (method, connection, address, body). |
| Transform data | Data comes from (the trigger or the answer of an earlier step), Rules (written here or a saved mapping), Open the mapper, Run only if. |
| Condition | A rule builder (is equal to, is not equal to, is greater than, is at least, is less than, is at most, is empty, is not empty; "All must be true" or "Any can be true") and the rule as editable text, for example steps.step_1.response.total > 100. |
| Run in parallel | Branches start together; the next step waits for all. |
| Repeat for each item | List to go through; inside ${item} and ${index}; Try the whole loop up to (times); the answer has count and items. |
| Run another flow | Flow (switched-off flows are marked), What it receives (name and value pairs), Repeat (optional list), Wait for it up to (seconds), Try up to (times). |
| Wait | Wait mode: For a length of time (1 second to 30 days), Until a date and time, Until something happens, Until a person approves. |
| SPARK action | Action, Entity, Record id, Values to write, Filter. |
| SFTP, Database, Queue, File rows, Sync | The parameters of the actions above, using connection and queue pickers. |
Messages from the designer check
| Message | Cause |
|---|---|
| "Add at least one step." | The canvas is empty. |
| "The trigger needs an event kind." / "The trigger needs a schedule." | The trigger type is chosen without its value. |
| "The trigger sample is not valid JSON." | |
| "NAME needs an address or a connection." | A call card without either. |
| "NAME has a body that is not valid JSON." | |
| "NAME needs a rule, for example input.amount > 100." | Empty condition. |
| "NAME has nothing in either branch." / "...in any branch." | |
| "NAME needs the list to go through." / "...has nothing inside it to repeat." | |
| "NAME needs the flow to run." | |
| "NAME needs the queue." / "needs a message written as JSON." | |
| "NAME needs the database connection." / "the statement to run." / "a value for :NAME." | |
| "NAME needs the SFTP connection." / "the file's path." | |
| "NAME shares its step code with another step." | Duplicate codes. |
Procedure: build and release a flow
- Select New flow in the designer, enter Name
Order to partnerand accept the codeorder-to-partner. - Select the trigger card. Choose "When a business event happens" and enter the event kind
order.created. Paste a sample such as{"id":"SO-1001","customer":"Acme Ltd","total":1200.5,"currency":"usd"}. - Add a Transform data card, open the mapper, and map
idtoorderId,totaltoamountwith a number transform. - Add a Call an API card: Method POST, Connection
partner-api, Path/events, Body{"event":"order.created","data":"${steps.step_1.response}"}, Try up to 3 times. - Select Test. Fix anything the Flow checker lists. Select Save.
- Select Deploy. The chip changes to
v1 - On. Publish a test event on Events and open the flow's history to see the run.
Permissions
integration.flow: view (list, get, validate, monitoring, AI explain), create (save, AI generate), publish (activate, deactivate, schedule, trigger event, trigger filter), execute (execute, test run, test step, publish test event), cancel, retry (resume, retry), viewHistory (versions, executions, run detail, dead runs, AI failure analysis), manage (webhook secret, go-live requirement, worker pool), delete. Without a permission the API returns 403 actor "X" lacks integration.flow.ACTION permission.
API and CLI
| Purpose | Request |
|---|---|
| List, get | GET /api/v1/integration/flows, GET /api/v1/integration/flows/{code} |
| Save | POST /api/v1/integration/flows with flowCode, pluginId, name, description, scope, definition |
| Validate | POST /api/v1/integration/flows/{code}/validate returns {"errors":[...]} |
| Switch on, off | POST .../{code}/activate (204, or 202 PENDING_APPROVAL), POST .../{code}/deactivate |
| Delete | DELETE /api/v1/integration/flows/{code} |
| Versions | GET .../{code}/versions |
| Schedule | PUT .../{code}/schedule with {"cronExpression":"0 0 9 * * MON-FRI"}; an empty value clears it |
| Trigger event, filter | PUT .../{code}/trigger-event with {"eventType":"order.created"}; PUT .../{code}/trigger-filter with {"expression":"..."} |
| Run now | POST .../{code}/execute with the input object; header X-Idempotency-Key optional. Returns {"executionId":N,"status":"QUEUED"} |
| Test | POST .../{code}/test-run (works while switched off; run marked TEST), POST .../{code}/test-step with step, input, steps |
| Inbound call | POST /api/v1/integration/flows/webhooks/{code} (see below) |
| Runs | GET .../{code}/executions?pageIndex&pageSize (page size up to 500), GET /api/v1/integration/flow-executions/{id}, .../dead |
| Run control | POST /api/v1/integration/flow-executions/{id}/cancel, /resume, /retry, /ai-analyze-failure |
| Monitoring | GET /api/v1/integration/flows/monitoring, GET .../flows/workers, POST .../flows/workers/resize with {"size":N} |
| AI | POST .../flows/ai-generate with {"prompt":"..."}, POST .../{code}/ai-explain |
| Publish a trigger event | POST .../flows/events/publish with eventType, payload |
Inbound receiver: the caller sends a JSON object body (up to 256 KB) with the X-Tenant-Id header. When the flow has a signing secret the call must carry webhook-id, webhook-timestamp and webhook-signature (v1, plus the base64 HMAC-SHA256 of id.timestamp.body, timestamp within 300 seconds), or the older webhookSecret query parameter. Failures: 401 "missing or incorrect signature or webhookSecret", 413 "the request body is larger than 256 KB", 429 "too many webhook calls; try again shortly" (default 300 per minute per tenant), 400 "the body must be a JSON object". A flow with no secret is open to anyone with the address. Set or clear the secret with PUT .../{code}/webhook-secret and {"secret":"..."}.
| Command | Purpose |
|---|---|
erp flow list, erp flow get <code> | Read. |
erp flow save <file.json> | Save a file {flowCode, name, description, scope, definition}; validated by the engine before it is written. |
erp flow activate <code>, erp flow deactivate <code> | Switch on or off. |
erp flow execute <code> [--input <json-string-or-@file>] | Start one run. |
erp flow require-golive-approval <code> on|off | Require a second person to switch the flow on. |
erp integration run flow <key> [--input ...] | Start through the endpoint applications use. |
erp integration health | Needs-attention summary. |
A complete flow definition, accepted by the validator (it reshapes an order and posts it with retries):
json
{
"steps": [
{
"code": "step_1",
"type": "MAP",
"dependsOn": [],
"source": "${input}",
"mapping": {
"fields": [
{ "target": "orderId", "source": "id", "required": true },
{ "target": "customer", "source": "customer", "transforms": ["trim"] },
{ "target": "amount", "source": "total", "transforms": ["number"] },
{ "target": "currency", "source": "currency", "transforms": ["upper"] }
]
}
},
{
"code": "step_2",
"type": "REST",
"method": "POST",
"dependsOn": ["step_1"],
"url": "/events",
"connectionCode": "target-system",
"body": { "event": "order.created", "data": "${steps.step_1.response}" },
"timeoutSeconds": 30,
"retry": { "enabled": true, "maxAttempts": 3, "backoff": "EXPONENTIAL", "initialDelaySeconds": 2, "maxDelaySeconds": 60 }
}
]
}Limits and behaviour
- Worker pool: default minimum 2 and maximum 50 workers, scaling 2 at a time. A run that shows RUNNING with no progress for 600 seconds is moved to DEAD.
POST /api/v1/integration/runis limited to 120 runs a minute per tenant.- Scheduled flows are evaluated by a tenant-by-tenant sweep on a tick; a schedule is not a precise timer.
- Step requests and responses are stored per attempt with sensitive fields masked at read time.
Errors and troubleshooting
| Message | Cause | Fix |
|---|---|---|
a step is missing its "code" / duplicate step code "X" | Step code absent or repeated. | Give each step a unique code. |
step "X" is missing "method" / is missing "url" (or a "connectionCode") | A REST step without a call. | Add the method and an address or connection. |
step "X" depends on unknown step "Y" | dependsOn names a missing step. | Correct the code. |
step "X" has an unknown runAfter value "Y" | Not SUCCESS, FAILED or SKIPPED. | |
step "X" has runAfter but nothing before it to wait for | runAfter on a root. | Add a dependency. |
step "X" needs the list to go through / needs at least one step inside the loop | Loop incomplete. | |
step "X" needs an action / needs a mapping / needs the flow to run | APP, MAP or FLOW step incomplete. | |
step "X" must wait between 1 second and 30 days | DELAY out of range. | |
step "X" must give up waiting between 1 second and 90 days | WAIT_EVENT or WAIT_APPROVAL timeout out of range. | |
step "X" has an onTimeout that is not FAIL or CONTINUE | ||
step "X" has conditions that are not a set of at most 10 field and value pairs | match too large. | |
the date is more than a year away, which is the longest a run can wait | WAIT_UNTIL too far. | |
flows are calling each other more than 5 levels deep | Run another flow chain too long. | |
invalid JSON: ... | The definition could not be parsed. | |
403 lacks integration.flow.publish permission | Missing right. | Grant the right. |
| 422 on execute | The flow is not ACTIVE, or another state prevents queueing. | Switch it on or use test-run. |
Templates
A catalog of ready-made integrations. Choosing one installs a draft flow, creates the connections it needs without secrets, and opens it in the designer switched off.
Where to find it
Studio Explorer > Workspace > Integrations > Templates. Page key integration-templates. Also Start from a template on Integration Flows.
Key concepts
| Status | Label | Meaning |
|---|---|---|
ready | Ready to use | Verified against a stand-in service in automated tests. |
untested | Not tested with the real service | A starting point to try before relying on it. |
planned | Planned | Listed but cannot be installed. The button reads "Not available yet". |
Screen
A search box ("Search templates, apps or words") matches name, summary, tags and vendors. The left column filters by Category and by Readiness. Each card shows the vendor initials, category, status, name, summary, vendor chips, the trigger and the step count. Selecting a card opens a dialog with the description, the status note, "How it works" (starting trigger and an outline of the steps), "What you need" and, for installable templates, a name field.
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Address (per connection) | text | the template's usual address | Required when the template has none | Must start with https:// or http://. |
| Name for your flow | text | the template's name | No | The flow code is the template key, or KEY-2, KEY-3 when taken. |
Use this template is disabled for planned templates and while a required address is empty. After install the result dialog lists next steps (add each secret, test, publish) and offers Open in the designer.
Catalog shipped with the platform
| Key | Category | Status | Trigger |
|---|---|---|---|
event-to-webhook | Getting started | ready | event |
fan-out-two-systems | Getting started | ready | event |
route-by-amount | Orders | ready | event |
scheduled-check-with-alert | Monitoring | ready | schedule |
hubspot-contact-from-customer | CRM | untested | event |
jira-issue-on-failure | Support | untested | event |
sendgrid-email-on-event | Notifications | untested | event |
slack-message-on-event | Notifications | untested | event |
teams-message-on-event | Notifications | untested | event |
razorpay-payment-to-invoice | Payments | planned | |
shopify-order-to-sales-order | Orders | planned | |
zoho-crm-lead-from-customer | CRM | planned |
Permissions
integration.template / view lists and reads; install installs.
API
GET /api/v1/integration/templates?category=&status=&q=, GET /api/v1/integration/templates/{key}, POST /api/v1/integration/templates/{key}/install with {"flowCode": "...", "name": "...", "connectionAddresses": {"CONNECTION_CODE": "https://..."} }. The response has flowCode, name, connectionsCreated, connectionsReused and nextSteps. An installed flow is saved with plugin id studio, switched off, with the template's event trigger or schedule set. No erp command installs templates.
Errors and troubleshooting
| Message | Cause | Fix |
|---|---|---|
the flow code must be lower-case letters, digits, dot, dash or underscore | Invalid flowCode. | |
a flow with the code "X" already exists | Requested code taken. | Choose another or leave empty. |
the address for "NAME" is needed: HELP | A connection without a usual address and none supplied. | Enter the address. |
the address for "NAME" must start with https:// or http:// | ||
this template is not available yet: NOTE (409) | Planned template. |
Mappings
A mapping turns one JSON document into another by declarative rules. Nothing in a mapping runs code: sources are dotted paths, transforms come from a fixed list. A field that cannot be mapped is reported as an issue (target and reason, never the value) and the rest still maps.
Where to find it
Studio Explorer > Workspace > Integrations > Mappings. Page key mappings.
Fields
Dialog Add mapping (an existing mapping opens with Open):
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name | text | empty | Yes | The code is generated from it while new. |
| Description | text | empty | No | |
| Rules (JSON) | JSON object | a starter with three fields | Yes | Must contain a fields list. |
| Sample to try it on (JSON) | JSON object | a starter sample | Used only by Try it. "Nothing is saved or sent when you try it." |
Grid columns: Mapping, About, Version, Changed by (user and date).
Rule fields
| Key | Type | Description |
|---|---|---|
target | string, required | Dotted output path, customer.name builds nested objects. |
source | string | Dotted input path, with [0] for lists. |
template | string | Text with ${path} placeholders. |
formula | string | An expression, see below. |
default | any | Used when the value is empty. A rule needs one of source, template, formula or default. |
required | boolean | A missing value is the issue "required value is missing". |
lookup | string | Name of a table inside the mapping's lookups object or of a shared Lookup Table. A table inside the mapping wins. |
valueMap | object | Direct value replacement, checked before lookup. |
transforms | list | Applied in order: trim, upper, lower, string, number, integer, boolean (true, yes, y, 1 / false, no, n, 0), digitsOnly, substring:from:to, replace:old:new, date:inPattern:outPattern. |
type | string | string, number, integer or boolean. Checked after transforms. |
pattern | regex | The whole value must match. |
minLength, maxLength, min, max | number | Length and numeric bounds. |
Formula operators: + - * / %, == != < <= > >=, && || !. Literals: numbers, 'text', true, false, null. Functions: if, coalesce, isEmpty, concat, upper, lower, trim, length, substring, replace, contains, startsWith, endsWith, join, number, text, round, abs, min, max, sum, today, now, addDays. A formula is at most 2000 characters.
Actions
| Action | Effect | API |
|---|---|---|
| Add mapping, Open | Opens the dialog. | GET /api/v1/integration/mappings/{code} |
| Try it | Applies the unsaved rules to the sample and shows "Every rule worked on this sample." or "N rule(s) did not work on this sample." with each issue and the output. | POST /api/v1/integration/mappings/test |
| Save | Creates or replaces by code; the version rises by one. | PUT /api/v1/integration/mappings/{code} |
| Delete | Removes the mapping. | DELETE /api/v1/integration/mappings/{code} |
Example
json
{
"fields": [
{ "target": "customer.name", "source": "fullName", "transforms": ["trim", "upper"], "required": true },
{ "target": "country", "source": "countryName", "lookup": "countries" },
{ "target": "amount", "source": "total", "transforms": ["number"], "min": 0 }
],
"lookups": { "countries": { "India": "IN" } }
}For the sample {"fullName":" ada lovelace ","countryName":"India","total":"12.50"} the output is {"customer":{"name":"ADA LOVELACE"},"country":"IN","amount":12.50}.
Permissions
integration.mapping: view (list, get, test, apply), manage (save, delete).
Limits and behaviour
At most 500 fields per mapping and 512 KB of rules. Saving validates structure (targets present, transforms known, lookups defined, patterns valid, formulas parse). POST /api/v1/integration/mappings/{code}/apply applies a saved mapping to a sample. No erp command manages mappings.
Errors and troubleshooting
| Message | Cause | Fix |
|---|---|---|
| "The rules is not valid JSON." / "The rules must be a JSON object." | Editor content. | Correct the JSON. |
the mapping is not valid: TARGET - needs a source, a template, a formula or a default | A rule has no value source. | |
... - unknown transform "X" | Transform not in the list. | |
... - lookup "X" is not defined | No table of that name in the mapping or shared tables. | |
... - the pattern is not valid | Regex error. | |
spec needs a fields list / spec is larger than 512 KB | ||
Issue value is not of type number | Type check failed after transforms. | |
Issue transform "number" could not be applied | Value is not numeric. |
Lookup Tables
A lookup table keeps values such as country codes in one place so any mapping can look them up by name.
Where to find it
Studio Explorer > Workspace > Integrations > Lookup Tables. Page key lookup-tables.
Fields
Dialog Add lookup table:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name | text | empty | Yes | |
| Description | text | empty | No | |
| Entries (one per line: what you receive=what you want) | text | empty | The first = splits the line, so a value may contain =. Blank lines are ignored. A line without a key shows "Line N needs a key, then =, then the value." The helper shows the entry count and the example India=IN. |
When the table is used, the dialog shows "Used by the mappings: ... Changing entries changes them all." Grid columns: Table, About, Entries, Changed by.
Actions and API
| Action | API |
|---|---|
| Open | GET /api/v1/integration/lookups/{code} (includes usedBy) |
| Save | PUT /api/v1/integration/lookups/{code} with {"name":"Countries","description":"...","entries":{"India":"IN"} } |
| Delete | DELETE /api/v1/integration/lookups/{code} |
| List | GET /api/v1/integration/lookups |
Permissions
Same resource as mappings: integration.mapping / view and manage.
Limits and errors
At most 20000 entries. Values must be single values, not objects or lists.
| Message | Cause |
|---|---|
a lookup table holds at most 20000 entries | Too many entries. |
an entry has an empty key | |
the value for "X" must be a single value | |
the table is used by the mappings: A, B (409) | Delete refused while mappings use it. |
code must be lower-case letters, digits, dot, dash or underscore |
Integrations
The governed release path for an integration. An integration definition names the flow and optional mapping that implement it, and moves through approval stages before it is switched on. Switching a definition on switches its flow on; switching it off switches the flow off.
Where to find it
Studio Explorer > Workspace > Integrations > Integrations. Page key integration-definitions.
Fields
Dialog Add integration:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name | text | empty | Yes | Code generated from it. |
| What it does | text | empty | No | |
| Direction | select | Send to the other system | Yes | outbound, inbound (Receive from the other system) or bidirectional (Both ways). |
| How it runs | select | Live, as things happen | Yes | online, offline (In batches, from files) or hybrid (Both). |
| Starts on this event | text | empty | No | Example order.created. |
| Flow that runs | select | Not chosen yet | Needed to validate | |
| Mapping | select | None | Needed for inbound |
Editing an existing integration shows "Saving a change sends this integration back to draft, and switches its flow off if it was running, so it is checked and approved again." and lists its current problems.
Stages
| Status | Label | Moves to | Permission needed |
|---|---|---|---|
DRAFT | Draft | TEST | manage |
TEST | Testing | VALIDATED, DRAFT | manage |
VALIDATED | Checked | APPROVED, DRAFT | approve for APPROVED, manage for DRAFT |
APPROVED | Approved | ACTIVE, DRAFT | activate for ACTIVE |
ACTIVE | Running | INACTIVE | activate |
INACTIVE | Switched off | ACTIVE, DRAFT | activate for ACTIVE |
Row buttons are named by the target: Back to draft, Start testing, Mark as checked, Approve, Switch on, Switch off. Open edits, History lists every move with time, user, from and to and note, and the delete button is disabled while ACTIVE. Chips: Integrations, Running, Approved but not switched on, In draft or testing. Approving and switching on are separate rights from editing, so the author need not be the releaser.
Moving to VALIDATED or ACTIVE is refused while problems exist: "Choose the flow that runs this integration."; The flow "X" does not exist.; The mapping "X" does not exist.; mapping rule problems; and "An integration that receives data needs a mapping." for inbound and bidirectional integrations.
API
GET /api/v1/integration/definitions, GET .../{code} (adds problems), GET .../{code}/history, PUT .../{code} with name, description, direction, mode, eventType, flowCode, mappingCode, DELETE .../{code}, POST .../{code}/transition with {"to":"TEST","note":"..."}. Errors: 409 "from DRAFT it can only go to TEST", 409 "switch it off before deleting it", 422 with the problems. Permission resource integration.definition: view, manage, approve, activate. No erp command.
Events
Business events that happened, kept durably so they can be searched and sent again. Flows and webhooks that listen for an event receive it at least once.
Where to find it
Studio Explorer > Workspace > Integrations > Events. Page key integration-events.
Screen
Chips: Events recorded, Kinds shown, Sent again. A filter "Only this kind" (for example hcm.employee.created) re-queries the list (up to 100 shown). Columns: Event (kind and event id), About (business object and record number), From (source application), When, Sent again (replay count). Row actions: Details (event id, version, time, trace id, changed fields and the data) and Send again.
Send a test event dialog:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Event kind | text | empty | Yes | Example order.created. At most 200 characters. |
| About (optional) | text | empty | No | Business object, for example Order. |
| Record number (optional) | text | empty | No | |
| Details (JSON, optional) | JSON object | empty | No | "The details must be a JSON object, like {"total": 10}." / "The details are not valid JSON." |
The event is recorded and goes to every switched-on flow and webhook listening for that kind. Send again replays the stored event to the same listeners and keeps the original event id.
API
| Purpose | Request |
|---|---|
| Publish | POST /api/v1/integration/events with eventType, optional eventVersion (default 1), sourceApplication, businessObject, businessObjectId, changedFields, data (up to 256 KB), correlationId, idempotencyKey. Returns 202, or 200 with duplicate: true. |
| Search | GET /api/v1/integration/events?eventType=&businessObject=&businessObjectId=&correlationId=&page=&size= (size up to 200) |
| Read | GET /api/v1/integration/events/{eventId} |
| Replay | POST /api/v1/integration/events/{eventId}/replay |
A missing correlation id is taken from the current request or generated. Permission integration.event: view, publish, replay. Errors: eventType is required (up to 200 characters), event data is larger than 256 KB. No erp command.
Failed Items
One list of everything that failed for good: flow runs in status FAILED or DEAD and outbound webhook deliveries that failed for good, that nobody has resolved. An item can be inspected, corrected and sent again, or set aside with a note.
Where to find it
Studio Explorer > Workspace > Integrations > Failed Items. Page key dead-letters.
Screen
A chip "Waiting for a decision: N" (or "Nothing is waiting") and filters All, Flow run, Webhook delivery. Columns: What failed (flow code or webhook code, with kind and id), Why (the recorded error, or "No reason was recorded"), When.
| Action | Effect | API |
|---|---|---|
| Look and fix | Opens the item with its error and the original input (flow run input or webhook payload) as editable JSON. "The content must be a JSON object." / "The content is not valid JSON." | GET /api/v1/integration/dead-letters/{type}/{id} |
| Send again | Replays unchanged. A flow run is retried as a new run; a webhook delivery is requeued. | POST .../{type}/{id}/replay |
| Send again with these changes | Replays with the corrected content. A flow starts a new run with the corrected input; a webhook payload is replaced then requeued. The original stays as it was. | POST .../{type}/{id}/replay with {"input":{...} } |
| Set aside | Removes it from the list with an optional note kept in the audit log. | POST .../{type}/{id}/discard with {"note":"..."} |
type is flow_execution or webhook_delivery. Replay returns replayed, corrected and newExecutionId or deliveryId; if it fails again the item returns to the list.
Permissions and errors
Resource integration.deadletter: view, replay, discard. Lists are 50 per page by default, up to 200.
| Message | Cause |
|---|---|
type must be flow_execution or webhook_delivery | Bad type in the path. |
no open dead letter (404) | Already resolved or never failed. |
delivery is no longer dead (409) | The webhook delivery changed state. |
input is not valid JSON |
Approvals and Waiting Runs
Lists the approval requests that flows are waiting on, and everything paused runs are waiting for. A flow asks for an approval with a Wait card in "Until a person approves" mode, which is a WAIT_APPROVAL step.
Where to find it
Studio Explorer > Workspace > Integrations > Approvals and Waiting Runs. Page key flow-approvals.
Tabs
| Tab | Content |
|---|---|
| To approve (N) | Pending requests. Columns Request (title and details), Flow (code and run number), Who can answer, Asked, Gives up. Actions Approve and Reject. A Mine switch shows requests assigned to the signed-in person or to anyone. |
| Waiting runs (N) | Paused runs. Columns Flow (code, run, step), Waiting for (kind chip: A length of time, A date and time, An event, A person's approval, with a sentence such as "The event payment.received (orderId = A-1)"), Since, Until / gives up, Started by. |
| Answered | History with Outcome (approved, rejected, timed out, cancelled), who answered and when. |
The answer dialog shows the details, a warning "Rejecting stops the flow with an error." when the step has stopIfRejected, and an optional Comment of up to 1000 characters. "The flow can use it, and it is kept with the answer."
Request statuses
| Status | Meaning |
|---|---|
PENDING | Waiting for an answer. |
APPROVED | Approved; the run continues with approved true. |
REJECTED | Rejected; the run continues with approved false, or fails if stopIfRejected. |
TIMED_OUT | No answer before timeoutSeconds; the step fails or continues per onTimeout. |
CANCELLED | The run was cancelled. |
The WAIT_APPROVAL step
json
{
"code": "hold",
"type": "WAIT_APPROVAL",
"dependsOn": ["create"],
"params": {
"title": "Approve order ${input.orderNo}",
"details": "Total ${input.total}",
"timeoutSeconds": 172800,
"onTimeout": "FAIL",
"stopIfRejected": false,
"assignees": ["finance.lead"]
}
}title is required; timeoutSeconds is required, 1 second to 90 days (the designer defaults to 2 days); onTimeout is FAIL or CONTINUE; assignees is a list of user ids, empty meaning anyone with the approve right. Later steps read approved, decidedBy and comment. Creating a request publishes approval.requested; answering publishes approval.decided.
API and permissions
GET /api/v1/integration/approvals?status=&limit=&mine=, POST /api/v1/integration/approvals/{id}/decide with {"approved":true,"comment":"..."}, GET /api/v1/integration/waits?limit=. Resource integration.flow: view for the lists, approve to answer. A request for specific people can be answered by others only with manage; otherwise 403 "this request is for specific people, and "X" is not one of them". Errors: 400 "say whether it is approved or rejected", 400 "the comment is longer than 1000 characters", 409 "This request was already answered, or the flow is no longer waiting for it." No erp command.
Go-Live Approvals
A flow or synchronization can be marked so that switching it on needs the approval of a different person. The request appears here.
Where to find it
Studio Explorer > Workspace > Integrations > Go-Live Approvals. Page key golive-approvals.
How it is used
- Set the requirement:
erp flow require-golive-approval order-to-partner onorerp sync require-golive-approval hr-people on(orPUT /api/v1/integration/flows/{code}/require-golive-approvalandPUT /api/v1/integration/syncs/{code}/require-golive-approvalwith{"required":true}). Needsmanage. - When someone activates the flow or enables the synchronization, no switch-on happens. The API answers 202 with
{"status":"PENDING_APPROVAL","request":{...} }and the request is listed. - A different person with the publish right selects Approve or Reject and may add a comment (up to 1000 characters, "Kept with the answer."). Approving switches the item on straight away.
Tabs: To approve (N) with columns Wants to switch on (code and kind: Flow or Synchronization), Asked by, Asked; and Answered with Outcome (approved, rejected, cancelled), Answered by and Asked by.
Statuses
PENDING, APPROVED, REJECTED, CANCELLED.
Permissions and errors
integration.flow / view lists; publish answers.
| Message | Cause |
|---|---|
| "the person who asked cannot also approve this request" (403) | Self-approval is refused. |
| "this request was already approved" (409) | Already answered. |
| "no such request" (404) |
GET /api/v1/integration/golive-requests?status=, POST /api/v1/integration/golive-requests/{id}/decide with {"approved":true,"comment":"..."}. erp integration health reports the number of pending requests.
Trace an Event
Follows one business event across every flow run, event, queue message and synchronization run that carries the same correlation id, in time order. Only what happened is shown, never message contents.
Where to find it
Studio Explorer > Workspace > Integrations > Trace an Event. Page key integration-trace.
Screen
Enter the correlation id (up to 100 characters) and select Trace. The id is shown in the event details and in server logs. The outcome chip is one of:
| Outcome | Label | Rule |
|---|---|---|
OK | Everything finished | Hops exist and none failed or is unfinished. |
IN_PROGRESS | Still in progress | A flow run is QUEUED, RUNNING or WAITING, a queue message is READY or IN_FLIGHT, or a sync run is RUNNING. |
FAILED | Something failed | A flow run FAILED or DEAD, a queue message DEAD, or a sync run FAILED. |
NOT_FOUND | Nothing found | No record carries the id. "Check it was copied whole; ids are case-sensitive." |
Columns: When, What happened (for example "Flow order-to-partner", "Event order.created", "Queue orders", "Synchronization hr-people" with details such as run number, who started it, attempts, created, updated, in conflict, failed), Kind and Status.
API and CLI
GET /api/v1/integration/trace/{correlationId} (letters, digits and . _ : -, up to 100; at most 500 hops per kind). Permission integration.flow / view. erp trace <correlationId> [--json] prints the same, for example:
text
f51b6f74-28d1-499b-a144-8875e6462cc7: OK (2 hops)
2026-09-28 08:08:29.883 event queue.message.received about message 29
2026-09-28 08:08:29.894 flow live-handler run #102 SUCCESS (EVENT - event:queue.message.received)A flow started by a schedule starts its own trace. Server log lines carry the same id: erp logs tail --grep <correlationId>. Error: 400 "the correlation id is up to 100 letters, digits and . _ : -".
Related
Overview, Triggers and Synchronization, Connections, Move between environments, Connect to another system, Send events with webhooks.
