> For the complete documentation index, see [llms.txt](https://developer.celigo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.celigo.com/api/api-reference/integrations-and-flows/flows.md).

# Flows

Flows orchestrate how data moves between systems. A flow chains one or more page generators (exports that produce records) into a pipeline of page processors (lookups and imports), with optional routers for conditional branching. Flows run on a cron schedule, on demand, or in response to real-time events, and expose endpoints for running, monitoring, and managing per-step errors.

### Flow schema

## The Flow object

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"components":{"schemas":{"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]}}}}
````

## List flows

> Returns all flows in the account.

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"parameters":{"After":{"name":"after","in":"query","required":false,"description":"Opaque cursor for forward pagination. Pass the value from the `Link`\nresponse header (`rel=\"next\"`) to fetch the next page.","schema":{"type":"string"}},"Include":{"name":"include","in":"query","required":false,"description":"Comma-separated list of fields to project into each returned record.\nTriggers summary projection: the response contains a minimal identity\nset (`_id`, `name`, plus resource-specific fields) with the requested\nfields added on top. Supports dot notation for nested fields.\nMutually exclusive with `exclude`.","schema":{"type":"string"}},"Exclude":{"name":"exclude","in":"query","required":false,"description":"Comma-separated list of fields to strip from the default response.\nUnlike `include`, does not trigger summary projection — returns the\nfull record with the named fields removed. Protected identity fields\n(e.g. `name`) cannot be stripped. Mutually exclusive with `include`.","schema":{"type":"string"}}},"schemas":{"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows":{"get":{"summary":"List flows","description":"Returns all flows in the account.","operationId":"listFlows","tags":["Flows"],"parameters":[{"name":"_abstractFlowId","in":"query","description":"Filter to instance flows that inherit from this abstract (multi-instance) flow.","schema":{"type":"string","format":"objectId"}},{"name":"externalId","in":"query","description":"Filter to flows matching this exact external identifier.","schema":{"type":"string"}},{"name":"name","in":"query","description":"Filter to flows whose name contains this value — a case-insensitive\nsubstring match, not an exact match; regex metacharacters match\nliterally and surrounding whitespace is trimmed. An empty value is\nignored; a value longer than the maximum is rejected with 400\n`invalid_query_param`.","schema":{"type":"string","maxLength":150}},{"name":"disabled","in":"query","description":"Filter by the `disabled` flag.","schema":{"type":"boolean"}},{"name":"_integrationId","in":"query","description":"Filter to flows belonging to this integration.","schema":{"type":"string","format":"objectId"}},{"name":"sort_by","in":"query","description":"Sort order for the results. `lastExecutedAt` sorts by most recent\nexecution first, with never-run flows at the tail. The sort key is\nupdated when a run starts, so a long-running flow can appear lower\nthan one that started more recently.","schema":{"type":"string","enum":["lastExecutedAt"]}},{"name":"includeInstances","in":"query","description":"When true, instance flows generated from abstract (multi-instance)\nflows are included in the results, which otherwise list only\nregular and abstract flows.","schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of flows to return per page.","schema":{"type":"integer","minimum":1}},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"Successfully retrieved list of flows.","headers":{"Link":{"description":"RFC-5988 pagination links. When more pages remain, includes a `<...>; rel=\"next\"` entry;\nabsent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Flow"}}}}},"204":{"description":"No flows match — the account has none, or the filters excluded every flow."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
````

## Create a flow

> Creates a new flow. Flows are created enabled (\`disabled: false\`) by default — set\
> \`disabled: true\` on create if the flow is not ready to run.\
> \
> At minimum, provide \`name\` and \`\_integrationId\`. Do not leave the flow enabled with a\
> \`schedule\` unless it is fully configured — it will start executing on schedule. For\
> abstract/instance patterns, create the abstract flow first, then create instances with\
> \`\_abstractFlowId\`.\
> \
> When \`\_integrationId\` is omitted or \`null\`, the flow is auto-assigned to the\
> account's "Standalone flows" integration rather than left standalone.\
> If that migration integration does not exist on the account, the\
> request fails with \`422 standalone\_flows\_not\_supported\`. A value that is\
> not a well-formed ObjectId is rejected with \`400 invalid\_ref\` before the\
> flow is validated, and an id that names no integration in the account\
> fails with \`422 invalid\_ref\`. Always pass an explicit \`\_integrationId\`.\
> \
> \`schedule\` is validated on every write even when \`disabled\` is true, so a\
> disabled flow cannot be parked with a broken schedule: \`422 invalid\_value\`\
> when the expression cannot be parsed into a schedule, \`422\
> schedule\_not\_supported\` when its runs would be less than a minute apart\
> (which is also what free text produces).

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Fields for creating or updating a flow.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both. The `schedule` field uses Celigo's 6-field cron format (not standard 5-field).","required":["name"],"allOf":[{"$ref":"#/components/schemas/FlowBase"}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows":{"post":{"summary":"Create a flow","description":"Creates a new flow. Flows are created enabled (`disabled: false`) by default — set\n`disabled: true` on create if the flow is not ready to run.\n\nAt minimum, provide `name` and `_integrationId`. Do not leave the flow enabled with a\n`schedule` unless it is fully configured — it will start executing on schedule. For\nabstract/instance patterns, create the abstract flow first, then create instances with\n`_abstractFlowId`.\n\nWhen `_integrationId` is omitted or `null`, the flow is auto-assigned to the\naccount's \"Standalone flows\" integration rather than left standalone.\nIf that migration integration does not exist on the account, the\nrequest fails with `422 standalone_flows_not_supported`. A value that is\nnot a well-formed ObjectId is rejected with `400 invalid_ref` before the\nflow is validated, and an id that names no integration in the account\nfails with `422 invalid_ref`. Always pass an explicit `_integrationId`.\n\n`schedule` is validated on every write even when `disabled` is true, so a\ndisabled flow cannot be parked with a broken schedule: `422 invalid_value`\nwhen the expression cannot be parsed into a schedule, `422\nschedule_not_supported` when its runs would be less than a minute apart\n(which is also what free text produces).","operationId":"createFlow","tags":["Flows"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"201":{"description":"Flow created successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Flow"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
````

## Get a flow

> Returns the complete configuration of a flow, including its page generators, processors,\
> routers, schedule, and all nested settings.\
> \
> Walk \`pageGenerators\[].\_exportId\` and \`pageProcessors\[].\_importId\` (or\
> \`routers\[].branches\[].pageProcessors\[]\`) to discover the exports and imports wired into\
> the flow. For the full resource objects, use \`GET /v1/flows/{\_id}/descendants\` instead of\
> fetching each one individually. Instance flows (\`\_abstractFlowId\` is set) have sparse\
> top-level fields because the runtime merges them with the abstract flow's config.

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}":{"get":{"summary":"Get a flow","description":"Returns the complete configuration of a flow, including its page generators, processors,\nrouters, schedule, and all nested settings.\n\nWalk `pageGenerators[]._exportId` and `pageProcessors[]._importId` (or\n`routers[].branches[].pageProcessors[]`) to discover the exports and imports wired into\nthe flow. For the full resource objects, use `GET /v1/flows/{_id}/descendants` instead of\nfetching each one individually. Instance flows (`_abstractFlowId` is set) have sparse\ntop-level fields because the runtime merges them with the abstract flow's config.","operationId":"getFlowById","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id.","required":true,"schema":{"type":"string","format":"objectId"}},{"name":"mergeInstance","in":"query","description":"When true and the flow is an instance of an abstract (multi-instance) flow,\nthe response merges the abstract flow's configuration into the instance.\nWithout this, instance flows return a sparse object containing only\n`_abstractFlowId`, `overrides`, and instance-level fields — no\n`pageGenerators` or `routers`.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Flow retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Flow"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
````

## Update a flow

> Replaces the entire flow configuration. All fields not included in the request body are\
> reset to defaults — this is a full replace, not a merge.\
> \
> Always \`GET\` the flow first, modify the response, and \`PUT\` back — sending a partial body\
> erases omitted fields. To change a single field (e.g. \`disabled\`, \`schedule\`), prefer\
> \`PATCH\` over \`PUT\`. Read-only fields (\`\_id\`, \`createdAt\`, \`lastModified\`) in the request\
> body are silently ignored.

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Fields for creating or updating a flow.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both. The `schedule` field uses Celigo's 6-field cron format (not standard 5-field).","required":["name"],"allOf":[{"$ref":"#/components/schemas/FlowBase"}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}":{"put":{"summary":"Update a flow","description":"Replaces the entire flow configuration. All fields not included in the request body are\nreset to defaults — this is a full replace, not a merge.\n\nAlways `GET` the flow first, modify the response, and `PUT` back — sending a partial body\nerases omitted fields. To change a single field (e.g. `disabled`, `schedule`), prefer\n`PATCH` over `PUT`. Read-only fields (`_id`, `createdAt`, `lastModified`) in the request\nbody are silently ignored.","operationId":"updateFlow","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"200":{"description":"Flow updated successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Flow"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
````

## Delete a flow

> Deletes a flow. Soft-deleted and retained in the recycle bin for 30 days.\
> Scheduled executions are stopped and any running jobs are cancelled.\
> \
> Check \`GET /v1/flows/{\_id}/dependencies\` first — if other resources reference this flow,\
> the delete is blocked. Soft-deleted flows can be restored via the recycle bin endpoints\
> within 30 days.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-dependency-conflict":{"description":"The resource has dependents that must be deleted first. Each entry\nin the `errors` array names one blocking resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flows/{_id}":{"delete":{"summary":"Delete a flow","description":"Deletes a flow. Soft-deleted and retained in the recycle bin for 30 days.\nScheduled executions are stopped and any running jobs are cancelled.\n\nCheck `GET /v1/flows/{_id}/dependencies` first — if other resources reference this flow,\nthe delete is blocked. Soft-deleted flows can be restored via the recycle bin endpoints\nwithin 30 days.","operationId":"deleteFlow","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id.","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Flow deleted successfully."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-dependency-conflict"}}}}}}
```

## Patch a flow

> Partially updates a flow using a JSON Patch document (RFC 6902).\
> \`replace\`, \`add\`, and \`remove\` operations are accepted only on the following\
> whitelisted paths:\
> \
> \| Path | Description |\
> \|------|-------------|\
> \| \`/name\` | Flow display name |\
> \| \`/description\` | Flow description |\
> \| \`/disabled\` | Enable or disable the flow |\
> \| \`/logging/debugUntil\` | Debug logging expiry (ISO-8601; at most the license's \`logging.maxDebugDuration\` minutes ahead, 422 beyond the cap) |\
> \| \`/logging/mode\` | Logging mode |\
> \| \`/runPageGeneratorsInParallel\` | Run page generators in parallel |\
> \| \`/aiDescription\` | AI-generated description object |\
> \| \`/schedule\` | Celigo 6-field cron string (same as PUT \`schedule\`) |\
> \| \`/timezone\` | IANA timezone string |\
> \
> All other paths are rejected with 422, except pointers nested under \`/schedule\`\
> (such as \`/schedule/cron\`): \`schedule\` is a string, so those return 204 and change\
> nothing. Send the whole cron string to \`/schedule\` instead.\
> \
> PATCH is safer than PUT for toggling \`disabled\` or arming debug logging because it won't\
> accidentally reset other fields. To arm debug logging, \`replace\` \`/logging/debugUntil\` with\
> a future ISO timestamp (up to the plan's cap, \`logging.maxDebugDuration\` minutes on the license\
> from \`GET /v1/licenses\`). To disarm it, \`remove\` \`/logging/debugUntil\`. A \`replace\` with a\
> past timestamp is refused with 422 ("Debug logging end time must be in the future.") and\
> leaves the window open, so to end a window early with \`replace\` alone, set a time a few\
> seconds ahead.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"JsonPatchRequest":{"type":"array","description":"A JSON Patch document (RFC 6902). Send an array of patch\noperations on whitelisted fields — all other paths are rejected\nwith 422.","minItems":1,"items":{"$ref":"#/components/schemas/JsonPatchOperation"}},"JsonPatchOperation":{"type":"object","description":"A single JSON Patch operation (RFC 6902).","required":["op","path"],"properties":{"op":{"type":"string","enum":["replace","add","remove"],"description":"The operation to perform."},"path":{"type":"string","description":"JSON Pointer (RFC 6901) to the field to patch. Only\nwhitelisted paths are accepted — unlisted paths return\n`422` with `\"<path> is not a whitelisted property\"`."},"value":{"description":"The new value to set. Required for `replace` and `add`, omit for `remove`."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}":{"patch":{"summary":"Patch a flow","description":"Partially updates a flow using a JSON Patch document (RFC 6902).\n`replace`, `add`, and `remove` operations are accepted only on the following\nwhitelisted paths:\n\n| Path | Description |\n|------|-------------|\n| `/name` | Flow display name |\n| `/description` | Flow description |\n| `/disabled` | Enable or disable the flow |\n| `/logging/debugUntil` | Debug logging expiry (ISO-8601; at most the license's `logging.maxDebugDuration` minutes ahead, 422 beyond the cap) |\n| `/logging/mode` | Logging mode |\n| `/runPageGeneratorsInParallel` | Run page generators in parallel |\n| `/aiDescription` | AI-generated description object |\n| `/schedule` | Celigo 6-field cron string (same as PUT `schedule`) |\n| `/timezone` | IANA timezone string |\n\nAll other paths are rejected with 422, except pointers nested under `/schedule`\n(such as `/schedule/cron`): `schedule` is a string, so those return 204 and change\nnothing. Send the whole cron string to `/schedule` instead.\n\nPATCH is safer than PUT for toggling `disabled` or arming debug logging because it won't\naccidentally reset other fields. To arm debug logging, `replace` `/logging/debugUntil` with\na future ISO timestamp (up to the plan's cap, `logging.maxDebugDuration` minutes on the license\nfrom `GET /v1/licenses`). To disarm it, `remove` `/logging/debugUntil`. A `replace` with a\npast timestamp is refused with 422 (\"Debug logging end time must be in the future.\") and\nleaves the window open, so to end a window early with `replace` alone, set a time a few\nseconds ahead.","operationId":"patchFlow","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonPatchRequest"}}}},"responses":{"204":{"description":"Flow patched successfully."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Clone a flow

> Creates a copy of a flow along with all transitive dependencies (exports, imports, scripts).\
> \`\_integrationId\` is required, and \`connectionMap\` is required when the flow references\
> connections — map a connection id to itself to reuse it, or to a different id to remap.\
> \
> Use \`GET /v1/flows/{\_id}/clone/preview\` first to see what resources will be created and\
> which connections need remapping. The cloned flow is always created \`disabled: true\`.

````json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"CloneRequest":{"type":"object","description":"Request body for cloning a flow.","required":["_integrationId"],"properties":{"name":{"type":"string","description":"Optional name for the cloned resource. If omitted, the server may generate a default clone name."},"_integrationId":{"type":"string","format":"objectId","description":"Integration to attach the cloned flow to. The server rejects clones without it\n(`invalid_ref` \"Integration not found for the given id\")."},"connectionMap":{"type":"object","description":"Mapping of original connection ids to replacement connection ids. Keys are source\nconnection ids on the original resource; values are target connection ids. Required\nwhen the flow references connections — omitting it fails with 400\n`invalid_connectionMap`. Map a connection to itself to reuse it in the clone.","additionalProperties":{"type":"string"}},"_stackId":{"type":"string","format":"objectId","description":"Stack that every stack reference in the cloned resources (hooks and wrapper\nconnections running on a stack) points at. Required when the clone preview reports\n`stackRequired: true`: without it the clone fails with 400 `stack_not_found`. The\nstack must belong to the target environment or be shared with it (404\n`stack_not_found` for an unknown id, 400 `invalid_stack` otherwise)."}},"additionalProperties":true},"CloneResponse":{"description":"Response body for a clone operation. Some clone endpoints return the cloned resource, while others may return a list of related created resources.","oneOf":[{"$ref":"#/components/schemas/Flow"},{"title":"Resource manifest","type":"array","items":{"type":"object","properties":{"model":{"type":"string","description":"Model name of the created resource (e.g., Flow, Export, Import)."},"_id":{"type":"string","format":"objectId","description":"Unique id of the created resource."},"name":{"type":"string","description":"Optional name of the created resource."}}}}]},"Flow":{"type":"object","required":["_id","name","disabled","logging","createdAt","lastModified"],"description":"Flow object as returned by the API.","allOf":[{"$ref":"#/components/schemas/FlowBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"logging":{"type":"object","readOnly":true,"description":"Flow-level execution logging state. Writable only through `PATCH /v1/flows/{_id}`\n(paths `/logging/mode` and `/logging/debugUntil`) — the server silently ignores\n`logging` in POST and PUT bodies.","properties":{"mode":{"type":"string","description":"Logging verbosity level.","enum":["accountLevel","basic","detailed"]},"debugUntil":{"type":"string","format":"date-time","description":"Temporary debug-level logging until this timestamp. The longest window is the\nplan's `logging.maxDebugDuration` (minutes) on the account's license\n(`GET /v1/licenses`); values beyond the cap are rejected with 422."}}},"hidden":{"type":"boolean","readOnly":true,"description":"When true, the flow is hidden from standard UI views but remains executable via\nAPI. Server-managed — ignored in POST and PUT bodies."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft flow auto-deletes. Server-computed when `draft` is set at\ncreation."},"numInstances":{"type":"integer","readOnly":true,"description":"Number of instance flows derived from this abstract flow."},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App connector that owns this flow. Assigned by the connector\nframework at install time — user creates that set it are rejected with 403\n`create_not_allowed`."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the flow's most recent execution. Absent until the flow has run at least once."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the flow's open errors were last resolved."},"free":{"type":"boolean","readOnly":true,"description":"When true, the flow is free to run and does not require a paid subscription."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this flow was created from."},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Source resource this flow was cloned or installed from."}}}]},"FlowBase":{"type":"object","description":"Writable flow fields shared by the request and response schemas.\n\nUse `pageProcessors` for simple linear flows or `routers` for conditional branching — never\ninclude both: a flow with both arrays non-empty is rejected with 422 `invalid_branched_flow_config`\n(\"Either routers or pageProcessors should be present in the flow configuration and not both.\").\nTurning a linear flow into a branching one moves its top-level steps into the branches.\nThe same import can be a step only once per flow: a second `pageProcessors` entry with its\n`_importId`, in the same array or another branch, fails with 422 `invalid_flow` (\"… already\nincluded as a pageProcessor\"). The `schedule` field uses Celigo's 6-field cron format (not\nstandard 5-field).","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the flow."},"description":{"type":"string","maxLength":5120,"description":"Free-text description of the flow's purpose."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this flow belongs to. Omitting it (or sending `null`) on\ncreate no longer produces a standalone flow — the flow is auto-assigned\nto the account's \"Standalone flows\" integration (or the create fails\nwith `422 standalone_flows_not_supported` when that integration is\nmissing). A value that is not a well-formed ObjectId is rejected with\n`400 invalid_ref` rather than auto-assigned. Always set it explicitly."},"schedule":{"type":["string","null"],"description":"Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.\nExplicit minute/hour lists, ranges, wildcards, and step forms (`*/N`) are all valid.\nLeave empty for event-driven or webhook-triggered flows. Validated on every\nwrite, including while `disabled` is true, so a flow cannot be parked disabled\nwith a broken schedule: `422 invalid_value` when the expression cannot be parsed\ninto a schedule (for example all wildcards, `? * * ? * *`), `422\nschedule_not_supported` when its runs would be less than a minute apart — which\nis also what free text such as `every 5 minutes` produces.\n\nA save can store a later minute than it was sent. A minute field that is 0, 15,\n30 or 45, a list made only of those minutes, a range that starts at minute 0, or a\n`*/N` step with N above 5 is stored 5 minutes later: `? 0 6 ? * *` as\n`? 5 6 ? * *`, `? 0,15,30,45 * ? * *` as `? 5,20,35,50 * ? * *`, `? 0-10 * ? * *`\nas `? 5-15 * ? * *`, and `? */15 * ? * *` as `? 5-59/15 * ? * *`. Any other minute\nfield is kept as sent, including `? */5 * * * *` and lists that mix in other\nminutes (`? 0,10,20,30,40,50 * ? * *`), and the other fields never change. POST,\nPUT and PATCH all store it this way, the response and later reads return the\nstored value, and scheduled runs start at the stored minutes, so a flow saved for\n06:00 runs at 06:05 (live-verified 2026-10-22)."},"timezone":{"type":["string","null"],"description":"IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC. The flow's\n`schedule` and each page generator's own `schedule` are read in this timezone; a page\ngenerator has no timezone of its own."},"disabled":{"type":"boolean","description":"When true, scheduled executions are suspended and the flow cannot be triggered.\nRunning jobs are allowed to complete.","default":false},"pageGenerators":{"type":"array","description":"Data sources (exports) that produce pages of records for the flow. Mutually exclusive with\ntop-level `pageProcessors` when `routers` is used.","items":{"$ref":"#/components/schemas/PageGenerator"}},"pageProcessors":{"type":"array","description":"Sequential processing steps (imports, lookups, routers). Mutually exclusive with `routers` —\nuse one or the other, not both.","items":{"$ref":"#/components/schemas/PageProcessor"}},"routers":{"type":"array","description":"Routers that direct records into branches. Mutually exclusive with top-level\n`pageProcessors` — a flow with no branching uses `pageProcessors` and no routers at all,\nexcept an abstract flow (`isAbstract`), which rejects top-level `pageProcessors` and so\nholds even a linear chain in a pass-through router. A router comes in two shapes: a\n**branching router** sets both `routeRecordsTo` and `routeRecordsUsing` and has two or\nmore branches (the router node you see in Flow Builder); a **pass-through router** sets\nneither, has exactly one branch, and is not drawn — it is the invisible joint that holds\nthe steps before the first branching router (they cannot sit in top-level\n`pageProcessors` once routers exist) and that merges branches back into shared steps.\nRecords enter at `routers[0]` and reach other routers only through `branches[].nextRouterId`,\nso the order of the rest of the array is not execution order; a flow edited in Flow Builder\ncan list its routers out of execution order.","items":{"$ref":"#/components/schemas/Router"}},"_exportId":{"type":"string","format":"objectId","description":"Source export of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_importId`\ninstead of `pageGenerators`/`pageProcessors`; the server accepts and serves both\nforms. Prefer `pageGenerators` for new flows."},"_importId":{"type":"string","format":"objectId","description":"Destination import of a simple (single source, single destination) flow — the legacy\npre-flow-builder model still produced by Data Loader flows. Paired with `_exportId`\ninstead of `pageGenerators`/`pageProcessors`. Prefer `pageProcessors` for new flows."},"_runNextFlowIds":{"type":["array","null"],"description":"Flow IDs to start when a run of this flow completes — the flow's \"Next integration flow\"\nsetting in the UI; a run that completes with record-level errors still starts them, a run\nthat fails or is canceled does not. Accepts null as equivalent to an empty list (the server\nalso serves null on documents saved that way). Each next flow starts from its own source\nsteps and receives no records; a trigger that fires while the next flow is already queued\nor running is dropped, not queued, so several completions in quick succession start it\nonce, and a flow listed here cannot be deleted while this flow still references it\n(422 `dependencies_not_deleted`).","items":{"type":"string","format":"objectId"}},"_runNextExportIds":{"type":"array","description":"Specific exports in other flows to trigger after completion.","items":{"type":"object","properties":{"_flowId":{"type":"string","format":"objectId","description":"Flow containing the export to trigger."},"_exportId":{"type":"string","format":"objectId","description":"Export to execute."}}}},"externalId":{"type":["string","null"],"description":"External identifier for correlating the flow with a record in another system."},"wizardState":{"type":"string","enum":["step2","step3","done"],"description":"Tracks how far the user has progressed through the flow setup wizard in the UI."},"settings":{"type":"object","description":"Custom key-value settings for this flow. At runtime the flow's steps read them\nunder the fixed scope key `flow` — e.g. the Handlebars expression\n`{{settings.flow.batchSize}}`, the Mapper 2.0 envelope path\n`$.settings.flow.batchSize`, or `options.settings.flow` in script hooks.","additionalProperties":true},"runPageGeneratorsInParallel":{"type":"boolean","description":"When true, all page generators start simultaneously instead of sequentially."},"autoResolveMatchingTraceKeys":{"type":"boolean","default":true,"description":"When true, a new error for a record whose trace key already has open errors on the same step\nauto-resolves the older ones, a later success for that record auto-resolves its open errors,\nand errors classified `intermittent` are retried automatically — up to four attempts, the\nfirst about 30 minutes after the error."},"isAbstract":{"type":"boolean","description":"Marks this as an abstract (multi-instance) flow — a reusable template that cannot be\nexecuted directly. Instance flows reference it via `_abstractFlowId` and provide `overrides`.\n\nConstraints: top-level `pageProcessors` are not allowed (use `routers` — a linear chain\nsits in one pass-through router with neither routing field set), cannot reference another\nabstract flow, cannot be a \"run next\" target, and cannot be unset while instances exist."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance inherits from. Immutable once set. The instance inherits\nthe flow graph and uses `overrides` to customize connections, schedules, and hooks."},"overrides":{"$ref":"#/components/schemas/Overrides"},"overridesHelper":{"$ref":"#/components/schemas/OverridesHelper"},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Flow grouping for organizing related flows in the UI. References an entry in the\nintegration's `flowGroupings` array (not a standalone collection); an id that is not\none of the flow's own integration's groupings — nonexistent, or a grouping of another\nintegration — fails POST and PUT with 422 `flowgrouping_not_belong`. Omit it or pass\n`null` to leave the flow in the integration's default section. At runtime the flow's\nsteps read the referenced group's `settings` under the fixed scope key `flowGrouping`\n(e.g. `{{settings.flowGrouping.<fieldId>}}`)."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this flow's checkpoint stays behind the referenced flow.\nUsed for parent-child data relationships where the parent must sync first."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export within a flow."},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"aliases":{"type":"array","description":"Named aliases that map to specific resources within the flow.","items":{"type":"object","properties":{"alias":{"type":"string","description":"Alias name."},"_exportId":{"type":"string","format":"objectId","description":"Export referenced by this alias."},"_importId":{"type":"string","format":"objectId","description":"Import referenced by this alias."},"_flowId":{"type":"string","format":"objectId","description":"Flow referenced by this alias."},"_connectionId":{"type":"string","format":"objectId","description":"Connection referenced by this alias."}}}},"draft":{"type":"boolean","description":"When true, this flow is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."},"preSave":{"type":"object","description":"Pre-save hook that runs a script before persisting flow changes.","properties":{"function":{"type":"string","description":"Function name to invoke."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the pre-save function."}}},"settingsForm":{"type":"object","description":"Form definition for collecting flow-level settings from users in the UI.","additionalProperties":true}}},"PageGenerator":{"type":"object","description":"A data source that produces pages of records for the flow. Page generators are the\nentry points of a flow; each references an export, can carry its own schedule, and\nmultiple generators can run in parallel when the flow enables it.","properties":{"_exportId":{"type":"string","format":"objectId","description":"Export that retrieves data from the source system. The server rejects page\ngenerator entries without a valid export reference unless the entry is a\nplaceholder still being set up (`setupInProgress: true`)."},"schedule":{"type":"string","description":"Cron expression for this specific generator, overriding the flow's main schedule.\nWhen omitted, the generator inherits the flow's schedule. It is read in the flow's\n`timezone`, and a flow with no flow-level `schedule` still runs on it. PATCH reaches\nthe flow-level `/schedule` and `/timezone` but not this field, so changing it is a full\nupdate of the flow."},"skipRetries":{"type":"boolean","default":false,"description":"When true, failed records from this generator are not retried — errors are logged\nand the flow continues. When false (the default), failed records are retried per\nplatform policy."},"setupInProgress":{"type":"boolean","description":"When true, the generator's configuration is still being set up in the UI and the step is not yet runnable."},"_keepDeltaBehindFlowId":{"type":"string","format":"objectId","description":"Coordinates delta timing so this generator's checkpoint stays behind the referenced\nflow, preventing child records from being processed before their parents."},"_keepDeltaBehindExportId":{"type":"string","format":"objectId","description":"Like `_keepDeltaBehindFlowId` but targets a specific export's delta timestamp."},"__startDateHelper":{"type":"string","readOnly":true,"description":"Server-managed scheduling bookkeeping written by the platform when a run\nstarts. Never send it: the API silently drops any client-supplied value."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["_exportId"]}},"PageProcessor":{"type":"object","description":"A processing step that operates on pages of records within a flow. Processors are\neither lookups (`type: export`) that enrich records or imports (`type: import`) that\nwrite records to a destination, and execute sequentially unless routed into branches.","properties":{"type":{"type":"string","description":"Selects whether this step runs a lookup export or an import, and which reference field applies.","enum":["export","import"]},"_exportId":{"type":"string","format":"objectId","description":"Lookup export that enriches incoming records. Required when `type` is `export`;\nthe referenced export must be configured as a lookup (`isLookup: true`)."},"_importId":{"type":"string","format":"objectId","description":"Import that writes records to the destination system. Required when `type` is `import`."},"proceedOnFailure":{"type":"boolean","description":"When true, records that fail in this processor continue to subsequent steps and the\nerror is logged. When false, failed records stop at this step."},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"hooks":{"type":"object","description":"Custom code hooks extending this processor's behavior.","properties":{"postResponseMap":{"type":"object","description":"Hook that runs after the step's response mapping completes. The function receives\n`options.postResponseMapData` (the records, with response mapping applied) and\n`options.responseData` (the step's per-record results, in the same order) and returns\n`postResponseMapData`, same length. A record an import step failed is in neither array\nunless `proceedOnFailure` is true. Then it is included, without the fields response\nmapping would have added, and its `responseData` entry has `statusCode` 422 and\n`errors` as an object keyed by index (`\"0\"`, `\"1\"`, ...) rather than an array. A\nsuccessful entry has no `errors`.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}},"setupInProgress":{"type":"boolean","description":"When true, the processor's configuration is still being set up in the UI and the step is not yet runnable."}},"if":{"properties":{"setupInProgress":{"const":true}},"required":["setupInProgress"]},"then":{},"else":{"required":["type"],"if":{"properties":{"type":{"const":"export"}},"required":["type"]},"then":{"required":["_exportId"]},"else":{"if":{"properties":{"type":{"const":"import"}},"required":["type"]},"then":{"required":["_importId"]}}}},"ResponseMapping":{"type":"object","description":"Merges fields from a step's response back onto the in-flight record so\ndownstream steps can read them. Applies to both lookup steps\n(`type: \"export\"`) and import steps (`type: \"import\"`); without it, the\nstep's response is discarded after the call.\n\n`fields` and `lists` are plain arrays — exactly the shape GET returns.\n\nExtract paths do NOT read the raw application response — the platform\nwraps every response in a canonical per-record envelope first, and\nextracts evaluate against that envelope:\n\n- **Lookup steps**: `{\"statusCode\": 200, \"data\": [<result records>],\n  \"errors\": []}` — `data` holds the records the lookup step returns,\n  AFTER the export's own `transform` and output `filter` have run, so\n  extracts must start from it and name transformed fields by their\n  transformed name: `data[0].name` copies a field of the first result,\n  `data` copies the whole result array. A bare result-record field name\n  (e.g. `name`) resolves to nothing and merges nothing, and so does the\n  raw response path a transform consumed. A lookup that groups its\n  results returns each group as an array inside `data`\n  (`\"data\": [[<row>, <row>]]`): `data[0][0].name` (or `data.0.0.name`)\n  reads the first row of the first group, and `data[0]` copies the group.\n- **Import steps**: `{\"id\": \"<destination record id>\", \"statusCode\": 200,\n  \"ignored\": false, \"errors\": [], \"_json\": <raw destination response>,\n  ...<response body fields flattened at the root>}` — use `id` for the\n  destination-assigned id and `_json.<path>` (or the flattened\n  `<path>`) for fields inside the destination's response body. The full\n  envelope (including `id`) is present on real runs and in flow-builder\n  previews; flow TEST runs never execute imports, and their envelope is\n  built from the import's saved `mockResponse`, or from the placeholder\n  `{\"id\": \"1234567890\", \"mockResponse\": \"replace me\"}` (numbered\n  `1234567890-1`, `1234567890-2`, … when a page holds several records)\n  — an `extract: \"id\"` in a test run merges that mock id, never a\n  destination record id.\n\nAn `extract` may also be a Handlebars expression. It evaluates against\nthe same envelope as a plain path, so every path inside `{{ }}` starts\nwhere the plain paths start — `{{data.0.name}}`,\n`{{#compare data.0.count \"==\" 1}}yes{{else}}no{{/compare}}`,\n`{{#if data.length}}found{{/if}}` on a lookup; `{{_json.order.id}}` or\n`{{id}}` on an import. Index arrays with dots inside Handlebars\n(`data.0.name` or `data.[0].name`; `data[0].name` renders nothing), and\nexpect a string result (`\"1\"`, `\"false\"`). There is no `record` object in\nthis context: `{{record.<anything>}}` renders nothing. Prefer a plain\npath when the value is simply copied.\n","properties":{"fields":{"type":"array","description":"Field mappings that copy individual values from the response\nenvelope onto the in-flight record.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within the canonical response envelope to copy the value\nfrom, or a Handlebars expression over that same envelope. For\nlookup steps, paths start from the envelope's `data` array\n(`data[0].x` and `data.0.x` are equivalent; `data` alone\ncopies every result) — a lookup result field written without\nthe `data` prefix resolves to nothing. For import steps, use\nthe envelope fields `id`, `statusCode`, `ignored`, `_json.<path>`\nfor the raw response body, or the body field itself at the\nenvelope root (`orderNumber` and `_json.orderNumber` read the\nsame value). A `[*]` wildcard is not honored here — `data[*].x`\nmerges nothing; iterate arrays with `lists` instead. Inside\nHandlebars, index with dots (`{{data.0.x}}`, never\n`{{data[0].x}}`) and never use a `record.` root.\n"},"generate":{"type":"string","description":"Field path on the in-flight record where the extracted value\nis stored, using dot notation for nesting. Downstream steps\nread the value at this path.\n"}}}},"lists":{"type":"array","description":"Array mappings that build a target array on the in-flight record\nfrom an array inside the response envelope — one output item per\nelement of the array the item extracts mark with `[*]` (`data[*].x`\nfor lookups, `_json.<arrayPath>[*].x` for imports); an empty source\narray yields an empty target array. Not needed for one-to-many\n(fan-out) merge-back, which uses plain field mappings.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"Array field created on the in-flight record to hold the\nmapped items.\n"},"fields":{"type":"array","description":"Field mappings applied to each item of the source array to\nproduce the corresponding target-array item.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"Full envelope path to the source value, with `[*]`\nmarking the array to iterate — `data[*].productId` for a\nlookup, `_json.items[*].sku` for an import. A path without\n`[*]` (e.g. `statusCode`) repeats the same envelope value\non every item; an item-relative name (`productId`)\nresolves to nothing and produces empty objects.\n"},"generate":{"type":"string","description":"Target field within each mapped array item."}}}}}}}}},"Router":{"type":"object","description":"Directs records into branches. A router comes in two shapes, told apart by whether\n`routeRecordsTo` and `routeRecordsUsing` are set: a **branching router** sets both and has two\nor more branches, each taking the records its `inputFilter` (or the router's `script`)\nmatches — the router node you see in Flow Builder; a **pass-through router** sets neither and\nhas exactly one branch that every record goes straight through — not drawn in Flow Builder,\nit is the joint that holds the steps before the first branching router and that merges\nbranches back into shared steps (branches rejoin only by pointing `nextRouterId` at the same\nrouter). A flow with no branching needs no routers — its steps go in top-level\n`pageProcessors` — unless it is abstract (`isAbstract`), where top-level `pageProcessors` are\nrejected and the chain sits in one pass-through router.\n","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the flow.\n\nUsed to reference this router from branches (`branches[].nextRouterId`)\nwhen chaining routers. Must be unique within the flow's router collection.\nUse at most 36 letters, digits, underscores and hyphens: a longer id, or one\nwith a space or a period, fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the\nrouter id.\").\n"},"name":{"type":"string","description":"Human-readable name for the router.\n\nDisplayed in the UI and logs to help identify the router's purpose.\n"},"routeRecordsTo":{"type":"string","description":"How many branches a record may continue down. Set together with `routeRecordsUsing` on a\nbranching router; leave both unset on a one-branch pass-through router.","enum":["first_matching_branch","all_matching_branches"]},"routeRecordsUsing":{"type":"string","description":"How a branching router decides which branch a record matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router.","enum":["input_filters","script"]},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n\nEnables custom routing logic that can't be expressed with filters.\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource"},"function":{"type":"string","description":"Function name that returns the branch name for each record"}}},"branches":{"type":"array","description":"List of branches that define different processing paths.\n\nEach branch has its own criteria and processing steps. Records are evaluated\nagainst branch criteria in the order defined.\n","items":{"$ref":"#/components/schemas/Branch"}}},"required":["id","branches"]},"Branch":{"type":"object","description":"Configuration for a single branch within a router that defines criteria and processing steps.\n\nEach branch represents a conditional path that records can take based on matching criteria.\nBranches are evaluated in order, and records are routed based on the router's strategy.\n","properties":{"name":{"type":"string","description":"Label for the branch, unique within the router. On a branching router it is shown on\nthe Flow Builder canvas, appears in logs, and is the value a routing script returns to\npick the branch — make it describe the branch's purpose. The single branch of a\npass-through router has no visible label; the server stores an empty string when the\nname is omitted.\n"},"description":{"type":"string","description":"Optional description explaining the branch's purpose and criteria.\n\nHelps document:\n- What types of records this branch handles\n- Business logic or rules applied\n- Why this branch exists\n"},"inputFilter":{"type":"object","description":"Filter criteria that determines which records match this branch.\n\nOnly used when the router's `routeRecordsUsing` is `input_filters`.\nRecords matching these criteria will be routed to this branch. A branch\nwithout an `inputFilter` matches every record, so under\n`first_matching_branch` the catch-all branch goes last.\n\nSend `version` and `rules` directly on `inputFilter` — not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import\nfilters use. A wrapped filter is saved without an error, but the branch is\nstored with no `inputFilter` and takes every record.\n","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`, the same version export and import filters use."},"rules":{"type":"array","description":"Filter expression array defining the matching criteria, in the platform's\nprefix-notation filter DSL: the first element is an operator name and the\nremaining elements are its operands, which may themselves be nested\nexpression arrays.\n\n```\n[operator, operand1, operand2, ...]\n```\n\nUses the same expression language as export/import filters\n(`Filter.expression.rules`): comparison operators (`equals`, `notequals`,\n`greaterthan`, `lessthan`, `startswith`, `contains`, `empty`, `matches`, ...),\nlogical operators (`and`, `or`, `not`), field access (`extract`, `settings`)\nand type conversions (`string`, `number`, `boolean`, `epochtime`).\n\nEvery `extract` must be wrapped in a type conversion. A bare\n`[\"extract\", \"<field>\"]` is refused when the flow is saved, with 422 \"Field\noperation extract must be called by a Type Conversion Operation but was called\nby equals.\" (the message names the operator that held it).\n\nExample — route records whose `isDeleted` field is the string \"false\":\n```json\n[\"equals\", [\"string\", [\"extract\", \"isDeleted\"]], \"false\"]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Null","type":"null"},{"title":"Object","type":"object"},{"title":"Array","type":"array"}]}}}},"pageProcessors":{"type":"array","description":"List of processors that execute for records routed to this branch.\n\nThese processors:\n- Execute in sequence for records matching this branch\n- Can include exports, imports, or nested routers\n- Have the same structure as flow-level page processors\n- Continue until completion or error (unless proceedOnFailure is set)\n","items":{"$ref":"#/components/schemas/PageProcessor"}},"nextRouterId":{"type":"string","description":"Chains this branch to another router: after the branch's pageProcessors\ncomplete, records continue to the router whose `id` matches this value.\n\nEnables sequential routing decisions where records pass through multiple\nrouters for complex branching logic. The server validates the reference —\na value that does not match any router `id` in the flow is rejected with\na 422 (\"Invalid nextRouterId is defined on the branch\").\n"},"branchId":{"type":"string","description":"Stable identifier for this branch, used to correlate branch-level state\n(for example dashboards and error reporting) across saves. Generated by\nthe server when omitted; a client-supplied value is kept as-is.\n"}}},"Overrides":{"type":"object","description":"Configuration overrides for flows that inherit from abstract flows.\n\nWhen a flow inherits from an abstract flow template, this object allows selective\noverriding of inherited configuration while maintaining the base structure.\n","properties":{"name":{"type":"string","description":"Override for the flow's display name"},"description":{"type":"string","description":"Override for the flow's description"},"settings":{"type":"object","description":"Override for custom flow settings.\n\nAllows modifying specific settings while inheriting others from\nthe abstract flow template.\n","additionalProperties":true},"timezone":{"type":"string","description":"Override for the flow's schedule timezone"},"_runNextFlowIds":{"type":"array","description":"Override list of flows to trigger after completion","items":{"type":"string"}},"_runNextExportIds":{"type":"array","description":"Override list of exports to trigger after completion","items":{"type":"object","properties":{"_flowId":{"type":"string","description":"The flow containing the export"},"_exportId":{"type":"string","description":"The specific export to trigger"}}}},"__listenerIdsToIndex":{"type":"array","readOnly":true,"description":"Server-managed listener index auto-populated by the platform on instance\nflows. Never send it as part of a request.","items":{"type":"string"}},"connections":{"type":"array","description":"Override connection configurations for abstract flow connections.\n\nMaps abstract connection placeholders to concrete connection instances.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract connection being overridden"},"_id":{"type":"string","description":"Concrete connection ID to use instead"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection to share concurrency limits with.\n\nUseful when multiple connections access the same system\nand need to share rate limiting.\n"}}}},"exports":{"type":"array","description":"Override configurations for exports in the abstract flow.\n\nAllows customizing export behavior while maintaining the flow structure. Each entry needs\nat least one field besides `_abstractId`; an entry with only `_abstractId` fails with 422\n(\"Export override must include at least one field in addition to _abstractId\").\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract export being overridden"},"_id":{"type":"string","description":"Existing export that replaces the abstract flow's export on this instance. This is\nhow an instance gets its own webhook URL: instances that keep the abstract flow's\nlistener share its URL, and one request to it runs every enabled instance."},"_connectionId":{"type":"string","description":"Override the connection used by this export"},"_keepDeltaBehindFlowId":{"type":"string","description":"Override delta synchronization settings"},"_keepDeltaBehindExportId":{"type":"string","description":"Override delta synchronization settings"},"schedule":{"type":"string","description":"Replaces the page generator's schedule for this instance, in the same\nCeligo 6-field cron format as the flow-level `schedule`. Parsed on every\nwrite regardless of `disabled`; an unparseable expression fails with\n`422 invalid_value` at `overrides.exports[i].schedule`."},"skipRetries":{"type":"boolean","description":"Override retry behavior"},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's export (lookup step), which reshape records the lookup returns."},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"pageSize":{"type":"integer","description":"Override page size for this export"},"dataURITemplate":{"type":"string","description":"Override URI template for error tracking"},"traceKeyTemplate":{"type":"string","description":"Override trace key generation"},"pathToMany":{"type":"string","description":"Override one-to-many path configuration"},"inputFilter":{"type":"object","description":"Override input filtering rules","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the matching criteria, in prefix notation — the operator first, followed by its operands, which may be nested expressions."}}},"groupByFields":{"type":"array","description":"Override grouping fields","items":{"type":"string"}},"test":{"type":"object","description":"Override test mode settings","properties":{"limit":{"type":"integer","description":"Overrides the test-mode record cap on the abstract flow's export — the total number of records a test run processes."}}},"delta":{"type":"object","description":"Override delta configuration","properties":{"dateField":{"type":"string","description":"Overrides the delta date field on the abstract flow's export — the record timestamp field(s) compared against the last successful run time to identify changed records. Accepts a single field or multiple comma-separated fields."},"dateFormat":{"type":"string","description":"Overrides the moment.js format string applied to the delta cutoff timestamp; ISO 8601 is used when unset."},"startDate":{"type":"string","description":"Overrides the fixed start timestamp used for the delta window on the abstract flow's export, in place of the last successful run time."},"lagOffset":{"type":"integer","description":"Overrides the buffer in milliseconds subtracted from the last successful run timestamp, creating an overlapping window that catches late-propagating records."},"endDateField":{"type":"string","description":"Overrides the record timestamp field used as the upper bound of the delta window on the abstract flow's export."}}},"once":{"type":"object","description":"Override once export settings","properties":{"booleanField":{"type":"string","description":"Overrides the once-mode tracking field on the abstract flow's export — the boolean field in the source system that is false for unprocessed records and set to true after successful processing."}}},"valueDelta":{"type":"object","description":"Override value delta settings","properties":{"exportedField":{"type":"string","description":"Overrides the field that tracks the last exported value on the abstract flow's export."},"pendingField":{"type":"string","description":"Overrides the field that tracks the pending (not yet exported) value on the abstract flow's export."}}},"webhook":{"type":"object","description":"Override webhook configuration","properties":{"token_crypt":{"type":"string","description":"Encrypted form of the webhook verification token, stored at rest."},"token_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook token."},"path":{"type":"string","description":"Overrides the location of the verification token on the abstract flow's webhook export — a JSON path into the request body or a query parameter name."},"key_crypt":{"type":"string","description":"Encrypted form of the webhook HMAC or public key, stored at rest."},"key_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook key."},"header":{"type":"string","description":"Overrides the name of the request header that carries the HMAC signature on the abstract flow's webhook export."},"username":{"type":"string","description":"Overrides the username used for basic-auth webhook verification on the abstract flow's export."},"password_crypt":{"type":"string","description":"Encrypted form of the basic-auth webhook password, stored at rest."},"password_salt":{"type":"string","description":"Salt used to encrypt the corresponding webhook password."},"successStatusCode":{"type":"integer","description":"Overrides the HTTP status code returned to the webhook caller after successful processing."},"successBody":{"type":"string","description":"Overrides the response body returned to the webhook caller after successful processing; ignored when the status code is 204."},"successMediaType":{"type":"string","description":"Overrides the Content-Type of successful webhook responses; must match the format of the success body."}}},"distributed":{"type":"object","description":"Override distributed processing settings","properties":{"bearerToken_crypt":{"type":"string","description":"Encrypted form of the distributed export's bearer token, stored at rest."},"bearerToken_salt":{"type":"string","description":"Salt used to encrypt the corresponding bearer token."}}},"hooks":{"type":"object","description":"Override hook configurations"},"transform":{"type":"object","description":"Override transformation settings"},"parsers":{"type":"array","description":"Override parser configurations","items":{"type":"object"}},"filters":{"type":"object","description":"Override filter configurations"},"formSchema":{"type":"object","description":"Override form schema"},"preSaveSchema":{"type":"object","description":"Override pre-save configuration"},"settings":{"type":"object","description":"Override export-specific settings","additionalProperties":true},"idLockTemplate":{"type":"string","description":"Override ID lock template"}}}},"imports":{"type":"array","description":"Override configurations for imports in the abstract flow.\n\nSimilar structure to export overrides but for import resources.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract import being overridden"},"_connectionId":{"type":"string","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"Override error handling behavior"},"responseMapping":{"$ref":"#/components/schemas/ResponseMapping"},"idLockTemplate":{"type":"string","description":"Overrides the ID lock template on the abstract flow's import — a handlebars template that generates a lock key so records resolving to the same key are not submitted concurrently."},"dataURITemplate":{"type":"string","description":"Overrides the data URI template on the abstract flow's import — a handlebars template that builds a link back to each record in the destination application's UI for error tracking."},"pathToMany":{"type":"string","description":"Overrides the one-to-many path on the abstract flow's import — the JSON path to child records within each parent record."},"blobKeyPath":{"type":"string","description":"Overrides the blob key path on the abstract flow's import — the path in the input record that holds the blob key identifying file content to import."},"filter":{"type":"object","additionalProperties":true,"description":"Overrides the filter on the abstract flow's import, which selects which incoming records are sent to the destination system."},"traceKeyTemplate":{"type":"string","description":"Overrides the trace key template on the abstract flow's import — a handlebars template controlling how each record's unique trace key is generated."},"parsers":{"type":"array","items":{"type":"object"},"description":"Overrides the parser configurations on the abstract flow's import."},"hooks":{"type":"object","additionalProperties":true,"description":"Overrides the hook configurations on the abstract flow's import — custom JavaScript hooks that run at fixed points in the import lifecycle."},"responseTransform":{"type":"object","additionalProperties":true,"description":"Overrides the response transform on the abstract flow's import, which reshapes the destination system's response after records are imported."},"mapping":{"type":"object","additionalProperties":true,"description":"Overrides the Mapper 1.0 mapping configuration on the abstract flow's import."},"mappings":{"type":"array","items":{"type":"object"},"description":"Overrides the Mapper 2.0 field mappings on the abstract flow's import, which transform incoming records into the destination system's field structure."},"lookups":{"type":"array","items":{"type":"object"},"description":"Overrides the lookup definitions on the abstract flow's import, referenced by its field mappings."},"settingsForm":{"type":"object","additionalProperties":true,"description":"Overrides the settings form definition on the abstract flow's import, which prompts users for values stored in `settings`."},"preSave":{"type":"object","additionalProperties":true,"description":"Overrides the preSave hook on the abstract flow's import — a JavaScript hook that executes before the resource is saved."},"settings":{"type":"object","additionalProperties":true,"description":"Overrides the custom settings on the abstract flow's import, accessible to hooks, filters, mappings, and handlebars templates at runtime."}}}},"routers":{"type":"array","description":"Override configurations for routers in the abstract flow.\n\nAllows customizing router behavior and branch configurations.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract router being overridden"},"name":{"type":"string","description":"Override router name"},"script":{"type":"object","description":"Override routing script","properties":{"_scriptId":{"type":"string","description":"Reference to the script resource containing the routing logic used in place of the abstract router's script."},"function":{"type":"string","description":"Function name within the script that returns the branch name for each record."}}},"branches":{"type":"array","description":"Override branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the abstract branch being overridden"},"name":{"type":"string","description":"Overrides the branch's display name within the router."},"description":{"type":"string","description":"Overrides the branch's description explaining its purpose and criteria."},"inputFilter":{"type":"object","description":"Overrides the branch's input filter — the criteria that determine which records are routed to this branch.","properties":{"version":{"type":"string","description":"Version of the filter expression format used by the rules; currently only \"1\" is supported."},"rules":{"type":"object","additionalProperties":true,"description":"Filter expression defining the branch's matching criteria, in prefix notation — the operator first, followed by its operands."}}}}}}}}}}},"OverridesHelper":{"type":"object","description":"Metadata for abstract flows that declares which fields in the flow's connections,\nexports, imports, and routers are overridable by instance flows.\n\nOnly valid on abstract flows (isAbstract: true). The backend rejects this field\non non-abstract flows. Each entry references a component of the abstract flow by\nits ID and lists the field names that instance flows are allowed to override.\n","properties":{"fields":{"type":"array","description":"Flow-level field names that instance flows may override (e.g., \"schedule\", \"timezone\")","items":{"type":"string"}},"connections":{"type":"array","description":"Declares which connection-level fields are overridable per abstract flow connection.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the connection in the abstract flow"},"fields":{"type":"array","description":"Field names on this connection that instance flows may override","items":{"type":"string"}}}}},"exports":{"type":"array","description":"Declares which export-level fields are overridable per abstract flow export.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the export in the abstract flow"},"fields":{"type":"array","description":"Field names on this export that instance flows may override","items":{"type":"string"}}}}},"imports":{"type":"array","description":"Declares which import-level fields are overridable per abstract flow import.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the import in the abstract flow"},"fields":{"type":"array","description":"Field names on this import that instance flows may override","items":{"type":"string"}}}}},"routers":{"type":"array","description":"Declares which router-level and branch-level fields are overridable per abstract flow router.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"ID of the router in the abstract flow"},"fields":{"type":"array","description":"Field names on this router that instance flows may override","items":{"type":"string"}},"branches":{"type":"array","description":"Per-branch override declarations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Index or ID of the branch in the abstract flow router"},"fields":{"type":"array","description":"Field names on this branch that instance flows may override","items":{"type":"string"}}}}}}}}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/clone":{"post":{"summary":"Clone a flow","description":"Creates a copy of a flow along with all transitive dependencies (exports, imports, scripts).\n`_integrationId` is required, and `connectionMap` is required when the flow references\nconnections — map a connection id to itself to reuse it, or to a different id to remap.\n\nUse `GET /v1/flows/{_id}/clone/preview` first to see what resources will be created and\nwhich connections need remapping. The cloned flow is always created `disabled: true`.","operationId":"cloneFlow","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id to clone.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneRequest"}}}},"responses":{"201":{"description":"Flow cloned successfully. Returns a manifest of the resources the clone created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
````

## Preview cloning a flow

> Returns a preview of resources that would be created by cloning this flow — the target flow\
> and all transitive dependencies (connections, exports, imports, scripts, async helpers,\
> lookup caches). No resources are created.\
> \
> Call this before \`POST /v1/flows/{\_id}/clone\` to discover which connections need remapping\
> in the \`connectionMap\` body field.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ClonePreviewResponse":{"type":"object","description":"Preview of the resources that would be created by a clone operation.\nEach object in the `objects` array represents a resource that will be\ncloned, including the target resource and all transitive dependencies\n(connections, scripts, exports, imports, etc.).\n","properties":{"objects":{"type":"array","description":"List of resources that would be created by the clone. Always includes\nthe target resource and may include transitive dependencies such as\nconnections, scripts, exports, imports, async helpers, and lookup caches.\n","items":{"type":"object","properties":{"model":{"type":"string","description":"The model type of the resource. Observed values include\nAsyncHelper, Connection, Export, Flow, Import, Integration,\nLookupCache, Script, and Tool.\n"},"doc":{"type":"object","description":"The full resource document that would be created by the clone.","additionalProperties":true}}}},"stackRequired":{"type":"boolean","description":"`true` when the resource or one of its dependencies references a stack (a hook or\nwrapper connection that runs on a stack). Send `_stackId` in the clone request: without\nit the clone fails with 400 `stack_not_found`."},"_stackId":{"type":["string","null"],"description":"The first stack the resource or a dependency references, or null. Pass it, or another\nstack in the target environment, as `_stackId` in the clone request; the clone points\nevery stack reference at that one stack."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/clone/preview":{"get":{"summary":"Preview cloning a flow","description":"Returns a preview of resources that would be created by cloning this flow — the target flow\nand all transitive dependencies (connections, exports, imports, scripts, async helpers,\nlookup caches). No resources are created.\n\nCall this before `POST /v1/flows/{_id}/clone` to discover which connections need remapping\nin the `connectionMap` body field.","operationId":"previewCloneFlow","tags":["Flows"],"parameters":[{"name":"_id","in":"path","description":"Flow id to preview cloning.","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Clone preview retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClonePreviewResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get a flow's descendant resources

> Returns the full resource objects for every import, export, and tool referenced by the flow.\
> This is a convenience endpoint that resolves the flow's entire dependency tree in a single\
> call — equivalent to reading the flow config and then fetching each referenced resource\
> individually, but without the N+1 round-trips.\
> \
> The returned arrays mirror the full resource shapes from \`GET /v1/imports/{\_id}\`,\
> \`GET /v1/exports/{\_id}\`, and \`GET /v1/tools/{\_id}\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowDescendantsResponse":{"type":"object","description":"The full resource objects for every import, export, and tool referenced by the flow. Useful for\nfetching a flow's entire dependency tree in a single call instead of resolving each resource\nindividually.","properties":{"imports":{"type":"array","description":"Import resources referenced by the flow's page processors.","items":{"type":"object","additionalProperties":true}},"exports":{"type":"array","description":"Export resources referenced by the flow's page generators and lookups.","items":{"type":"object","additionalProperties":true}},"tools":{"type":"array","description":"Tool resources referenced by the flow.","items":{"type":"object","additionalProperties":true}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/descendants":{"get":{"operationId":"getFlowDescendants","tags":["Flows"],"summary":"Get a flow's descendant resources","description":"Returns the full resource objects for every import, export, and tool referenced by the flow.\nThis is a convenience endpoint that resolves the flow's entire dependency tree in a single\ncall — equivalent to reading the flow config and then fetching each referenced resource\nindividually, but without the N+1 round-trips.\n\nThe returned arrays mirror the full resource shapes from `GET /v1/imports/{_id}`,\n`GET /v1/exports/{_id}`, and `GET /v1/tools/{_id}`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"The flow's descendant resources.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowDescendantsResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Summarize open errors across a flow's steps

> Returns a per-step count of currently open (unresolved) errors for the flow. Each entry carries the\
> step id and its open-error count; entries with zero errors still appear so the caller sees the full\
> step roster.\
> \
> For the full list of error records on a single step, call\
> \`GET /v1/flows/{\_id}/{\_stepId}/errors\`. For a whole-integration rollup, use\
> \`GET /v1/integrations/{\_id}/errors\`. \`lastErrorAt\` is only populated on entries with\
> \`numError > 0\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowErrorsResponse":{"type":"object","description":"Per-step summary of open errors for a flow. One entry per export or import step; entries with\n`numError: 0` still appear so the caller can see the full step list.","properties":{"flowErrors":{"type":"array","description":"Per-step error counts.","items":{"type":"object","properties":{"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step."},"numError":{"type":"integer","minimum":0,"description":"Count of currently open (unresolved) errors on this step. Only\nerrors within the account's data-retention window are counted —\nolder open errors are excluded."},"lastErrorAt":{"type":"string","format":"date-time","description":"Timestamp of the most recent open error on this step, scoped to\nthe account's data-retention window. Omitted when `numError` is 0."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/errors":{"get":{"operationId":"listFlowErrors","tags":["Flows"],"summary":"Summarize open errors across a flow's steps","description":"Returns a per-step count of currently open (unresolved) errors for the flow. Each entry carries the\nstep id and its open-error count; entries with zero errors still appear so the caller sees the full\nstep roster.\n\nFor the full list of error records on a single step, call\n`GET /v1/flows/{_id}/{_stepId}/errors`. For a whole-integration rollup, use\n`GET /v1/integrations/{_id}/errors`. `lastErrorAt` is only populated on entries with\n`numError > 0`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Per-step open-error summary.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowErrorsResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Replace a connection across a flow

> Replaces every occurrence of one connection with another across all exports, imports, and lookups\
> in the flow. This is the recommended way to swap connections during environment promotion\
> (e.g. credential rotation) — it updates all references atomically\
> instead of requiring per-resource PUTs.\
> \
> The replacement connection must exist and be of the same adaptor type as the original. If the\
> types do not match, the request is rejected with a 422.\
> \
> Use \`GET /v1/flows/{\_id}/descendants\` to verify which resources use a given connection\
> before replacing.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowReplaceConnectionRequest":{"type":"object","description":"Request body to replace one connection with another across all exports, imports, and lookups in a flow.\nBoth the current and replacement connection ids are required. The replacement connection must exist and\nbe of the same adaptor type as the original.","properties":{"_connectionId":{"type":"string","format":"objectId","description":"The id of the connection currently used by the flow's resources."},"_newConnectionId":{"type":"string","format":"objectId","description":"The id of the replacement connection to swap in."}},"required":["_connectionId","_newConnectionId"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/replaceConnection":{"put":{"operationId":"replaceConnectionOnFlow","tags":["Flows"],"summary":"Replace a connection across a flow","description":"Replaces every occurrence of one connection with another across all exports, imports, and lookups\nin the flow. This is the recommended way to swap connections during environment promotion\n(e.g. credential rotation) — it updates all references atomically\ninstead of requiring per-resource PUTs.\n\nThe replacement connection must exist and be of the same adaptor type as the original. If the\ntypes do not match, the request is rejected with a 422.\n\nUse `GET /v1/flows/{_id}/descendants` to verify which resources use a given connection\nbefore replacing.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowReplaceConnectionRequest"}}}},"responses":{"204":{"description":"Connection replaced successfully across all flow resources. No response body."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Trigger a flow run

> Queues an on-demand run of the flow and returns the parent job id. The run is \*\*asynchronous\*\*: the\
> response returns as soon as the job is queued; use \`GET /v1/jobs/{\_id}\` (with the returned \`\_jobId\`)\
> or \`GET /v1/flows/{\_id}/jobs/latest\` to poll for terminal status.\
> \
> The request body is optional. When omitted, the flow runs with its configured schedule behavior —\
> for delta flows this means using the current \`lastExportDateTime\` as the lower bound. Pass\
> \`export.startDate\` / \`export.endDate\` to set this run's delta window (they render as\
> \`{{lastExportDateTime}}\` / \`{{currentExportDateTime}}\`). On success, when \`export.endDate\` is\
> sent, the flow's checkpoint is left at that value, so an end date in the past moves the next\
> run's lower bound back. Pass \`\_exportIds\` to limit execution to a subset of the flow's\
> generators (useful for flows with many independent sources).\
> \
> Flow-level preconditions enforced by the platform:\
> \- The flow must not be \`disabled\`.\
> \- The flow must be in an enabled integration (when part of one).\
> \
> \
> To trace a run end-to-end, arm debug logging before calling this, then use the returned\
> \`\_jobId\` with the execution-log endpoints. For delta backfills, prefer passing explicit\
> \`startDate\`/\`endDate\` over editing the export's \`lastExportDateTime\`, and read the checkpoint\
> first (\`GET /v1/flows/{\_id}/lastExportDateTime\`): the override doesn't stay with one run, since\
> a successful run that sends \`endDate\` leaves the checkpoint there. Runs that export nothing\
> leave the checkpoint alone, so a stretch of empty runs needs no backfill once its cause is\
> fixed. A flow runs one instance at a time: a run requested while another\
> instance is queued or running is refused with \`409 job\_already\_queued\` ("Another instance\
> for this flow is already queued or running"), and a run-next-flow trigger that arrives in\
> that state is dropped rather than queued.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowRunRequest":{"type":"object","description":"Optional overrides for a manual flow run. Omit the body (or send `{}`) to run the flow with its default\nconfiguration.","properties":{"export":{"type":"object","description":"Delta-window override. When present, the run uses these dates in place of the flow's own\n`lastExportDateTime` / `currentExportDateTime`. Both fields are optional individually. The\noverride outlasts the run: a run that exports records leaves the flow's checkpoint at `endDate`.","properties":{"startDate":{"type":"string","format":"date-time","description":"ISO-8601 start of the delta window (maps to `lastExportDateTime`)."},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 end of the delta window (maps to `currentExportDateTime`). When the run exports\nrecords, the flow's checkpoint is left here, even when it is in the past, so the next run\nstarts from it."}}},"_exportIds":{"type":"array","description":"Optional subset of exports (page generators) to run. Omit to run every generator on the flow.\nUseful for multi-generator flows where only one source needs re-pulling.","items":{"type":"string","format":"objectId"}}}},"FlowRunResponse":{"description":"Response from `POST /v1/flows/{_id}/run`. Shape varies by run type:\n\n- **Single queued run** — an object with the parent job id (`_jobId`) plus queue metadata.\n- **On-demand / multi-export run** — an array of per-export run records.\n- **Rejected run** — an object with an `error` field. (Note: a run on a *disabled* flow is\n  rejected with HTTP 422 `invalid_flow`, not this shape.)\n\nCallers should branch on the response shape before treating it as a single job.","oneOf":[{"title":"single run","type":"object","additionalProperties":true,"required":["_jobId"],"description":"Single-job run result. Observed keys: `_jobId` (the parent job to poll), `_exportId`,\n`endDate`, `queueName`, and `message` (the internal queue payload — treat as opaque).","properties":{"_jobId":{"type":"string","format":"objectId","description":"Parent job id for the queued run; poll `GET /v1/jobs/{_id}` for status."}}},{"title":"per-export runs","type":"array","description":"Per-export run results for a multi-generator flow.","items":{"type":"object","additionalProperties":true}},{"title":"run rejected","type":"object","required":["error"],"description":"Run-rejected response.","properties":{"error":{"type":"string","description":"Human-readable reason the run was not started."}}}]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/run":{"post":{"operationId":"runFlow","tags":["Flows"],"summary":"Trigger a flow run","description":"Queues an on-demand run of the flow and returns the parent job id. The run is **asynchronous**: the\nresponse returns as soon as the job is queued; use `GET /v1/jobs/{_id}` (with the returned `_jobId`)\nor `GET /v1/flows/{_id}/jobs/latest` to poll for terminal status.\n\nThe request body is optional. When omitted, the flow runs with its configured schedule behavior —\nfor delta flows this means using the current `lastExportDateTime` as the lower bound. Pass\n`export.startDate` / `export.endDate` to set this run's delta window (they render as\n`{{lastExportDateTime}}` / `{{currentExportDateTime}}`). On success, when `export.endDate` is\nsent, the flow's checkpoint is left at that value, so an end date in the past moves the next\nrun's lower bound back. Pass `_exportIds` to limit execution to a subset of the flow's\ngenerators (useful for flows with many independent sources).\n\nFlow-level preconditions enforced by the platform:\n- The flow must not be `disabled`.\n- The flow must be in an enabled integration (when part of one).\n\n\nTo trace a run end-to-end, arm debug logging before calling this, then use the returned\n`_jobId` with the execution-log endpoints. For delta backfills, prefer passing explicit\n`startDate`/`endDate` over editing the export's `lastExportDateTime`, and read the checkpoint\nfirst (`GET /v1/flows/{_id}/lastExportDateTime`): the override doesn't stay with one run, since\na successful run that sends `endDate` leaves the checkpoint there. Runs that export nothing\nleave the checkpoint alone, so a stretch of empty runs needs no backfill once its cause is\nfixed. A flow runs one instance at a time: a run requested while another\ninstance is queued or running is refused with `409 job_already_queued` (\"Another instance\nfor this flow is already queued or running\"), and a run-next-flow trigger that arrives in\nthat state is dropped rather than queued.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunRequest"}}}},"responses":{"200":{"description":"Flow run accepted and queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"409":{"description":"Another instance of this flow is already queued or running. Wait for it to\nfinish (poll `GET /v1/flows/{_id}/jobs/latest`) and request the run again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get flow runtime chart stats

> Returns historical runtime statistics and chart buckets for a single flow.\
> Used by the proactive alerts UI to suggest and preview long-runtime\
> thresholds.\
> \
> This is not the job-dashboard aggregate API. Dashboard totals live at\
> \`POST /v1/flows/runs/stats\` (job spec). This path is\
> \`POST /v1/flows/{\_flowId}/runs/stats\`.\
> \
> Requires the proactive alerts feature flag and ClickHouse to be enabled for\
> the user. When ClickHouse is unavailable, returns\
> \`{ "clickhouseAvailable": false }\`.\
> \
> Time range constraints:\
> \- \`startTime\` is required (ISO 8601 UTC)\
> \- \`endTime\` defaults to now when omitted\
> \- Minimum range: 1 hour\
> \- Maximum range: 90 days\
> \- Granularity: hourly buckets for ranges ≤ 24h; daily buckets for longer ranges\
> \
> Chart \`alertsTriggered\` / \`totalAlertsTriggered\` count completed runs whose\
> runtime is \*\*strictly greater than\*\* the threshold used for the query.\
> That is a historical chart count, not the number of alert emails sent.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowRunsStatsRequest":{"type":"object","required":["type","startTime"],"properties":{"type":{"type":"string","description":"Request type.","enum":["runtimeSummary"]},"startTime":{"type":"string","format":"date-time","description":"Start of query window (ISO 8601 UTC). Must not be in the future."},"endTime":{"type":"string","format":"date-time","description":"End of query window (ISO 8601 UTC). Defaults to now. Must not be in the future."},"thresholdMinutes":{"type":"integer","minimum":5,"maximum":59940,"description":"Optional threshold override in minutes. When omitted, the response uses\n`statistics.suggestedThreshold` (ceil of p99 runtime, floored at 5).\nChart counts use this value with a strict greater-than comparison."}}},"FlowRunsStatsResponse":{"type":"object","description":"Runtime statistics response for the proactive alert threshold chart.\n\nThree shapes are possible:\n- **Summary** — `emptyState: false` with `statistics`, `chartEntries`, and\n  run totals. Returned when the time range has 3 or more completed runs.\n- **Empty state** — `{ _flowId, startTime, endTime, emptyState: true }` with\n  no chart data. Returned when the time range has fewer than 3 completed\n  runs.\n- **ClickHouse unavailable** — only `clickhouseAvailable: false`. Returned\n  when ClickHouse is not enabled for the caller.","properties":{"_flowId":{"type":"string","format":"objectId","description":"Echoed flow id."},"startTime":{"type":"string","format":"date-time","description":"Echoed query start time."},"endTime":{"type":"string","format":"date-time","description":"Echoed query end time."},"granularity":{"type":"string","description":"Bucket granularity for chart entries. Absent on empty-state and ClickHouse-unavailable responses.","enum":["hour","day"]},"thresholdMinutes":{"type":"integer","description":"Threshold used for chart alert-count computation. Absent on empty-state and ClickHouse-unavailable responses."},"totalRuns":{"type":"integer","description":"Total completed runs in the time range. Absent on empty-state and ClickHouse-unavailable responses."},"totalAlertsTriggered":{"type":"integer","description":"Count of completed runs in the window whose runtime is strictly greater\nthan `thresholdMinutes`. Historical chart metric only — not the number\nof alert emails sent. Absent on empty-state and ClickHouse-unavailable\nresponses."},"emptyState":{"type":"boolean","description":"`true` when the time range has fewer than 3 completed runs (no chart\ndata). `false` on summary responses. Absent on ClickHouse-unavailable\nresponses."},"truncated":{"type":"boolean","description":"True when totalRuns exceeds 5000. Indicates a high-volume warning; chart\ndata is still complete for the requested time range. Absent on\nempty-state and ClickHouse-unavailable responses."},"clickhouseAvailable":{"type":"boolean","description":"Present only when ClickHouse is not available for the caller. Value is\nalways `false` when present. Absent on successful summary and\nempty-state responses."},"statistics":{"type":"object","description":"Present on successful summary responses. Used by the UI for the\nsuggested threshold hint. Absent on empty-state and\nClickHouse-unavailable responses.","properties":{"suggestedThreshold":{"type":"integer","description":"Suggested threshold in minutes: ceil of the p99 completed-run\nruntime in the window, then floored at the platform minimum (5)."}}},"chartEntries":{"type":"array","description":"Chart data buckets. Present on successful summary responses. Absent on\nempty-state and ClickHouse-unavailable responses.","items":{"type":"object","properties":{"bucket":{"type":"string","description":"ISO hourly timestamp or YYYY-MM-DD date."},"totalRuns":{"type":"integer"},"alertsTriggered":{"type":"integer","description":"Completed runs in this bucket with runtime strictly greater than the query threshold."},"avgRuntimeMinutes":{"type":"number"},"p5RuntimeMinutes":{"type":"number"},"p95RuntimeMinutes":{"type":"number"}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_flowId}/runs/stats":{"post":{"operationId":"getFlowRuntimeChartStats","tags":["Flows"],"summary":"Get flow runtime chart stats","description":"Returns historical runtime statistics and chart buckets for a single flow.\nUsed by the proactive alerts UI to suggest and preview long-runtime\nthresholds.\n\nThis is not the job-dashboard aggregate API. Dashboard totals live at\n`POST /v1/flows/runs/stats` (job spec). This path is\n`POST /v1/flows/{_flowId}/runs/stats`.\n\nRequires the proactive alerts feature flag and ClickHouse to be enabled for\nthe user. When ClickHouse is unavailable, returns\n`{ \"clickhouseAvailable\": false }`.\n\nTime range constraints:\n- `startTime` is required (ISO 8601 UTC)\n- `endTime` defaults to now when omitted\n- Minimum range: 1 hour\n- Maximum range: 90 days\n- Granularity: hourly buckets for ranges ≤ 24h; daily buckets for longer ranges\n\nChart `alertsTriggered` / `totalAlertsTriggered` count completed runs whose\nruntime is **strictly greater than** the threshold used for the query.\nThat is a historical chart count, not the number of alert emails sent.","parameters":[{"name":"_flowId","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunsStatsRequest"}}}},"responses":{"200":{"description":"Runtime summary, empty-state payload, or ClickHouse-unavailable marker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunsStatsResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get a flow's trace-key patterns

> Returns the trace-key pattern for each page generator in the flow. Trace keys are used to\
> correlate source records with their downstream results in execution logs — they let you look up\
> "what happened to record X" without scanning the full log.\
> \
> Each entry in the returned array corresponds to one page generator (\`pgIndex\` matches the\
> zero-based position in the flow's \`pageGenerators\` array). The \`traceKeyPattern\` describes\
> which source-record fields and/or Handlebars templates are combined to produce the key.\
> \
> If both \`fields\` and \`templates\` are empty for a generator, the flow has no trace key configured\
> and log correlation must be done by position or other means. Trace keys are especially important\
> for fan-out flows where one source record produces many destination records.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowTraceKeyResponse":{"type":"array","description":"One entry per page generator in the flow. Each entry describes the trace-key pattern used to\ncorrelate source records with their downstream results in execution logs.","items":{"type":"object","properties":{"pgIndex":{"type":"integer","description":"Zero-based index of the page generator in the flow's `pageGenerators` array."},"traceKeyPattern":{"type":"object","description":"The pattern used to derive trace keys for records produced by this generator.","properties":{"fields":{"type":"array","description":"Source-record field paths that contribute to the trace key.","items":{"type":"string"}},"templates":{"type":"array","description":"Handlebars templates that produce trace-key segments.","items":{"type":"string"}}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/traceKey":{"get":{"operationId":"getFlowTraceKey","tags":["Flows"],"summary":"Get a flow's trace-key patterns","description":"Returns the trace-key pattern for each page generator in the flow. Trace keys are used to\ncorrelate source records with their downstream results in execution logs — they let you look up\n\"what happened to record X\" without scanning the full log.\n\nEach entry in the returned array corresponds to one page generator (`pgIndex` matches the\nzero-based position in the flow's `pageGenerators` array). The `traceKeyPattern` describes\nwhich source-record fields and/or Handlebars templates are combined to produce the key.\n\nIf both `fields` and `templates` are empty for a generator, the flow has no trace key configured\nand log correlation must be done by position or other means. Trace keys are especially important\nfor fan-out flows where one source record produces many destination records.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Trace-key patterns for each page generator in the flow.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTraceKeyResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get the flow's delta checkpoint

> Returns the flow-level "last export date/time" checkpoint — the most recent export timestamp across all\
> generators (exports) in the flow. This value is what gets substituted into the \`{{lastExportDateTime}}\`\
> Handlebars variable on the next delta run of any export in the flow.\
> \
> A run moves the checkpoint to its window end (\`{{currentExportDateTime}}\`) only when it exports\
> records. A run that exports nothing leaves it where it was, so after a stretch of empty runs the\
> next run that finds records reaches back to the last run that exported any. On success, when\
> \`POST /v1/flows/{\_id}/run\` sends \`export.endDate\`, the checkpoint is left at that value, so an end\
> date in the past moves the next run's lower bound back.\
> \
> A missing value (\`null\`, a flow that has never run) is not a full re-scan: the next delta run's\
> \`{{lastExportDateTime}}\` is the export's \`delta.startDate\` when set, and otherwise the run's own\
> timestamp, which picks up no earlier changes. A very old value re-reads everything changed since\
> then. This is the flow-scoped checkpoint; per-export checkpoints (for flows with multiple\
> generators that advance independently) are exposed on the export record's \`delta\` block.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"LastExportDateTimeResponse":{"type":"object","description":"The flow's delta checkpoint — the most recent export timestamp across all page generators in the flow.\nUsed by delta-export logic to compute the next `{{lastExportDateTime}}` value.","properties":{"lastExportDateTime":{"type":["string","null"],"format":"date-time","description":"ISO-8601 timestamp. `null` if the flow has never produced an export."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/lastExportDateTime":{"get":{"operationId":"getFlowLastExportDateTime","tags":["Flows"],"summary":"Get the flow's delta checkpoint","description":"Returns the flow-level \"last export date/time\" checkpoint — the most recent export timestamp across all\ngenerators (exports) in the flow. This value is what gets substituted into the `{{lastExportDateTime}}`\nHandlebars variable on the next delta run of any export in the flow.\n\nA run moves the checkpoint to its window end (`{{currentExportDateTime}}`) only when it exports\nrecords. A run that exports nothing leaves it where it was, so after a stretch of empty runs the\nnext run that finds records reaches back to the last run that exported any. On success, when\n`POST /v1/flows/{_id}/run` sends `export.endDate`, the checkpoint is left at that value, so an end\ndate in the past moves the next run's lower bound back.\n\nA missing value (`null`, a flow that has never run) is not a full re-scan: the next delta run's\n`{{lastExportDateTime}}` is the export's `delta.startDate` when set, and otherwise the run's own\ntimestamp, which picks up no earlier changes. A very old value re-reads everything changed since\nthen. This is the flow-scoped checkpoint; per-export checkpoints (for flows with multiple\ngenerators that advance independently) are exposed on the export record's `delta` block.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"The flow's current delta checkpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LastExportDateTimeResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Assign flows to a flow group

> Assigns one or more flows to a flow-grouping (section) within their integration. This is the\
> collection-level endpoint used by the UI's "move to section" action — it updates multiple flows in a\
> single call rather than requiring a per-flow \`PUT /v1/flows/{\_id}\` with a modified \`\_flowGroupingId\`.\
> \
> Every flow in \`\_flowIds\` must belong to the same integration, and \`\_flowGroupingId\` must be one\
> of that integration's \`flowGroupings\` — a grouping that does not exist or belongs to another\
> integration is rejected with 400 \`flowgrouping\_update\_error\`. Pass \`\_flowGroupingId: null\` or\
> omit it to move the flows back to the integration's default (Unassigned) section.\
> \
> Flow groupings are managed on the parent integration (\`PUT\` or \`PATCH /v1/integrations/{\_id}\`\
> with a modified \`flowGroupings\[]\` array) — create the group first, then call this to populate it.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"UpdateFlowGroupingRequest":{"type":"object","description":"Assign one or more flows to a flow group inside their parent integration. Replaces each flow's\ncurrent grouping membership; there is no multi-group membership model.","properties":{"_flowIds":{"type":"array","description":"The flows to move. All must belong to the same integration as the target flow group\n(400 `invalid_request` otherwise); ids that match no flow are silently skipped.","minItems":1,"items":{"type":"string","format":"objectId"}},"_flowGroupingId":{"type":["string","null"],"format":"objectId","description":"Grouping within the integration's `flowGroupings[]` to move the flows into. Must belong to\nthe flows' own integration (400 `flowgrouping_update_error` otherwise). Pass `null` or omit\nit to move the flows back to the integration's default section; an empty string is rejected\nwith 400 `invalid_ref`."}},"required":["_flowIds"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/updateFlowGrouping":{"put":{"operationId":"updateFlowGrouping","tags":["Flows"],"summary":"Assign flows to a flow group","description":"Assigns one or more flows to a flow-grouping (section) within their integration. This is the\ncollection-level endpoint used by the UI's \"move to section\" action — it updates multiple flows in a\nsingle call rather than requiring a per-flow `PUT /v1/flows/{_id}` with a modified `_flowGroupingId`.\n\nEvery flow in `_flowIds` must belong to the same integration, and `_flowGroupingId` must be one\nof that integration's `flowGroupings` — a grouping that does not exist or belongs to another\nintegration is rejected with 400 `flowgrouping_update_error`. Pass `_flowGroupingId: null` or\nomit it to move the flows back to the integration's default (Unassigned) section.\n\nFlow groupings are managed on the parent integration (`PUT` or `PATCH /v1/integrations/{_id}`\nwith a modified `flowGroupings[]` array) — create the group first, then call this to populate it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlowGroupingRequest"}}}},"responses":{"204":{"description":"Flows reassigned. Empty response body. Flow ids that match no flow in the account are\nsilently skipped, so an unknown `_flowIds` entry (or an empty list) also answers 204."},"400":{"description":"The request was rejected: the flows span more than one integration (`invalid_request`),\nthe grouping is not one of the flows' integration's `flowGroupings`\n(`flowgrouping_update_error`), or an id is not a well-formed ObjectId (`invalid_ref` —\nan empty-string `_flowGroupingId` fails this way; use `null` to ungroup).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## List open errors on a flow step

> Returns one page of currently-open (unresolved) errors for a single step (export or import) within\
> a flow. The step id is the \`\_exportId\` / \`\_importId\` from the flow's \`pageGenerators\[]\`,\
> \`pageProcessors\[]\`, or \`routers\[].branches\[].pageProcessors\[]\`.\
> \
> For a flow-wide rollup (per-step counts only), use \`GET /v1/flows/{\_id}/errors\` instead.\
> To scope the list to one specific run, pass \`\_flowJobId\` together with the required\
> \`occurredAt\_gte\`. Errors with a \`retryDataKey\` are retryable via \`POST .../retry\`;\
> connection-level errors typically lack one and require a full flow rerun to recover.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepErrorsResponse":{"type":"object","description":"One page of open errors for a flow step. Body-paginated: when `nextPageURL` is present, follow it\nto fetch the next page.","properties":{"errors":{"type":"array","description":"Open error records on this page.","items":{"$ref":"#/components/schemas/FlowStepError"}},"nextPageURL":{"type":"string","description":"URL for the next page. **Omitted entirely** (not `null`) when there are no further pages.\nSome clients strip a leading `/api` prefix before reissuing."}}},"FlowStepError":{"type":"object","description":"One open-error record on a flow step. Errors accumulate per `(flow, step)` pair as the flow runs;\nthey remain \"open\" until a user marks them resolved (`PUT .../resolved`) or submits a retry for\nthem (`POST .../retry` resolves them at submission, whatever the retry's outcome).","properties":{"errorId":{"type":"string","description":"Platform-assigned id for the error. This is the identifier you feed to assign / resolve /\ndelete-resolved endpoints via the `errorIds` (or `errors`) body array."},"occurredAt":{"type":"string","format":"date-time","description":"When the error happened (ISO 8601, UTC)."},"source":{"type":"string","description":"Step stage or system the error came from, such as `application`, `connection`, a hook\n(`pre_save_page_hook`, `post_response_map_hook`) or a filter (`output_filter`).\n`application` covers the step's whole call to the external system, not only its answer:\nbesides errors the destination returned, it marks a request that never got an answer,\nsuch as a URL template that failed to render (`handlebars_template_parse_error`) or a\nrefused connection, so read `code` and `message` with it. `GET /v1/errors/filterMetadata`\nlists the source values the errors filter accepts."},"code":{"type":"string","description":"Error code. For HTTP-sourced errors this is the stringified HTTP status (`\"500\"`, `\"401\"`).\nFor platform-classified errors it's a symbolic code (e.g. `\"script_error\"`)."},"message":{"type":"string","description":"Human-readable message. Frequently a JSON string that the adaptor received as a response body.\nStored cut to 500 characters: a longer message keeps its first 497 characters followed by\n`...`. A template parse error (`handlebars_template_parse_error`) repeats the whole template\nbefore its parse detail, so in a long template the detail is cut off; invoking the import\n(`POST /v1/imports/{_id}/invoke`) with the record returns the full message."},"oIndex":{"type":"string","description":"Zero-based index of the offending record within its batch (page). Paired with `_flowJobId` this\npinpoints the record inside the run's execution log."},"_flowJobId":{"type":"string","format":"objectId","description":"Id of the flow-run job this error came from. Use with `GET /v1/jobs/{_id}` for run context."},"traceKey":{"type":"string","description":"Upstream export/record identifier that produced this error — correlates the error back to the\nsource record across the execution log. Populated on every error in practice; callers doing\nrecord-level triage join on this field."},"classification":{"type":"string","description":"Category the platform derives from the error's code, message, and source — read-only, never\nset by users; `intermittent` errors are retried automatically while the flow's\n`autoResolveMatchingTraceKeys` is on. Absent when nothing matched with confidence. The value\nset is the `classification` dimension of the errors filter metadata."},"classifiedBy":{"type":"string","description":"`auto` on every classified error; absent on unclassified ones."},"reqAndResKey":{"type":"string","description":"Opaque key for the stored HTTP request+response pair associated with this error. Pass to\n`GET /v1/flows/{_id}/{_stepId}/requests/{reqAndResKey}` to fetch the decoded HTTP detail. Absent\nwhen the error was not produced by an HTTP adaptor."},"retryDataKey":{"type":"string","description":"Opaque key for the per-record data snapshot captured at the moment of failure. Populated on\nrecord-level errors (imports, transforms) where a retry means re-running the record; absent on\nconnection-level failures. Pass to `POST /v1/flows/{_id}/{_stepId}/retry` (as `retryDataKeys[]`)\nto retry, or to `GET /v1/flows/{_id}/{_stepId}/{retryDataKey}/data` to inspect / mutate the\nsnapshot before retry."},"purgeAt":{"type":"string","description":"Epoch-milliseconds timestamp (as a string) when the error record is scheduled for automatic\ndeletion from the queue. Drives the 30-day retention window by default."},"retryAt":{"type":"string","format":"date-time","description":"Present while the platform is auto-retrying this `intermittent` error. On a first-occurrence\nerror it is stamped about a minute after `occurredAt` and is not the first attempt time (that\nruns roughly 30 minutes out); on the error a failed attempt opens, it is the next scheduled\nattempt. Absent once the attempts are exhausted and on errors that are not auto-retried."},"tags":{"type":["array","null"],"description":"Tag names currently attached to this error, or `null` when no tags are set. Stored as the\nhuman-readable `tag` value (e.g. `\"Investigating\"`), **not** the short `tagId` code used when\nwriting via `PUT /v1/flows/{_id}/{_stepId}/tags`. Resolve names ↔ codes via `GET /v1/tags`.","items":{"type":"string"}},"assignedTo":{"type":"string","description":"Display name of the user currently assigned to this error for triage when the email resolves\nto a known account user (e.g. `\"Jane Doe\"`). When the email does not match a known\nuser, the literal email string is stored instead. Set via\n`PUT /v1/flows/{_id}/{_stepId}/errors/assign`. Absent when no assignment has been made."},"assignedBy":{"type":"string","description":"Mongo user id of the user who made the assignment. Absent when no assignment has been made."},"_assignedToUserId":{"type":"string","format":"objectId","description":"Mongo user id of the assignee. Paired with `assignedTo` for callers that need the id directly."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/errors":{"get":{"operationId":"listFlowStepErrors","tags":["Flows"],"summary":"List open errors on a flow step","description":"Returns one page of currently-open (unresolved) errors for a single step (export or import) within\na flow. The step id is the `_exportId` / `_importId` from the flow's `pageGenerators[]`,\n`pageProcessors[]`, or `routers[].branches[].pageProcessors[]`.\n\nFor a flow-wide rollup (per-step counts only), use `GET /v1/flows/{_id}/errors` instead.\nTo scope the list to one specific run, pass `_flowJobId` together with the required\n`occurredAt_gte`. Errors with a `retryDataKey` are retryable via `POST .../retry`;\nconnection-level errors typically lack one and require a full flow rerun to recover.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id — the step within the flow.","schema":{"type":"string","format":"objectId"}},{"name":"_flowJobId","in":"query","required":false,"description":"Only return errors produced by this flow-run job (each error record carries its\n`_flowJobId`). Must be paired with `occurredAt_gte` — without it the request fails with\n400 `invalid_flowjobid_param`.","schema":{"type":"string","format":"objectId"}},{"name":"occurredAt_gte","in":"query","required":false,"description":"Only return errors that occurred at or after this instant (inclusive). Required whenever\n`_flowJobId` is supplied; usable on its own to bound the window.","schema":{"type":"string","format":"date-time"}},{"name":"occurredAt_lte","in":"query","required":false,"description":"Only return errors that occurred at or before this instant (inclusive). Optional even when\nfiltering by `_flowJobId`; combine with `occurredAt_gte` to select a window.","schema":{"type":"string","format":"date-time"}},{"name":"tags","in":"query","required":false,"explode":true,"description":"Only return errors carrying at least one of the listed tags. Repeat the parameter once per\nvalue (`?tags=ShHjr&tags=untagged`); values are the account's short `tagId` codes from\n`GET /v1/tags`, not the tag names shown in each error's `tags` array — unknown values\n(including comma-joined lists) fail with 400 `invalid_tagid_param`. The literal value\n`untagged` matches errors with no tags and can be mixed with real tag ids.","schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"One page of open errors on this step.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepErrorsResponse"}}}},"400":{"description":"Invalid filter parameters. `invalid_flowjobid_param` — `_flowJobId` was supplied without\n`occurredAt_gte`. `invalid_ref` — `_flowJobId` is not a valid object id. `invalid_tagid_param` —\na `tags` value is not a known tag id (or `untagged`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Assign open errors to a user

> Tags a batch of open errors with an assignee for triage workflows. The errors stay open — this does\
> not resolve or retry them — they simply appear in the assignee's "my errors" view until another\
> action moves them.\
> \
> The \`email\` value is accepted verbatim and is not validated against the account's user list.\
> Re-assigning the same batch to a different user overwrites the prior assignment. Use\
> \`PUT .../errors/unassign\` to remove assignments entirely.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepErrorsAssignRequest":{"type":"object","description":"Request body for `PUT /v1/flows/{_id}/{_stepId}/errors/assign`. Assigns a batch of open errors to a\nuser by email; the errors remain open but are tagged with the assignee for triage views.","properties":{"errorIds":{"type":"array","description":"Ids of open errors to assign. Obtain from `GET /v1/flows/{_id}/{_stepId}/errors` → each entry's\n`errorId`. Platform caps batch size around ~1000; chunk larger sets client-side.","minItems":1,"items":{"type":"string"}},"email":{"type":"string","format":"email","description":"Email of the account user to assign the errors to. Must be a user who has access to the account;\nthe API does not create users implicitly."}},"required":["errorIds","email"]},"FlowStepAffectedErrorsResponse":{"type":"object","description":"Echo of which error records the mutation touched. Returned by `PUT .../errors/assign`.","properties":{"errorsToReturn":{"type":"array","description":"Error ids that were affected by the mutation.","items":{"type":"string"}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/errors/assign":{"put":{"operationId":"assignFlowStepErrors","tags":["Flows"],"summary":"Assign open errors to a user","description":"Tags a batch of open errors with an assignee for triage workflows. The errors stay open — this does\nnot resolve or retry them — they simply appear in the assignee's \"my errors\" view until another\naction moves them.\n\nThe `email` value is accepted verbatim and is not validated against the account's user list.\nRe-assigning the same batch to a different user overwrites the prior assignment. Use\n`PUT .../errors/unassign` to remove assignments entirely.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepErrorsAssignRequest"}}}},"responses":{"200":{"description":"Errors assigned. Body echoes which ids were affected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepAffectedErrorsResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Remove assignment from open errors

> Removes the assignee from a batch of open errors. The errors remain open — this is the inverse\
> of \`PUT .../errors/assign\`. Non-existent error ids are silently ignored (no error raised).\
> \
> The response's \`errorsToReturn\` contains only ids that were actually unassigned — ids that\
> were already unassigned or don't exist are omitted.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepErrorsUnassignRequest":{"type":"object","description":"Request body for `PUT /v1/flows/{_id}/{_stepId}/errors/unassign`. Removes the assignee from a\nbatch of open errors. Non-existent error ids are silently ignored.","properties":{"errorIds":{"type":"array","description":"Ids of open errors to unassign. Obtain from `GET /v1/flows/{_id}/{_stepId}/errors` → each\nentry's `errorId`. Non-existent ids are silently ignored (no error raised).","minItems":1,"items":{"type":"string"}}},"required":["errorIds"]},"FlowStepErrorsUnassignResponse":{"type":"object","description":"Response from `PUT /v1/flows/{_id}/{_stepId}/errors/unassign`. Echoes which error ids were\nactually unassigned — ids that were not found or were already unassigned are omitted.","properties":{"errorsToReturn":{"type":"array","description":"Error ids that were actually unassigned by this call.","items":{"type":"string"}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/errors/unassign":{"put":{"operationId":"unassignFlowStepErrors","tags":["Flows"],"summary":"Remove assignment from open errors","description":"Removes the assignee from a batch of open errors. The errors remain open — this is the inverse\nof `PUT .../errors/assign`. Non-existent error ids are silently ignored (no error raised).\n\nThe response's `errorsToReturn` contains only ids that were actually unassigned — ids that\nwere already unassigned or don't exist are omitted.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepErrorsUnassignRequest"}}}},"responses":{"200":{"description":"Errors unassigned. Body echoes which ids were actually affected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepErrorsUnassignResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get a signed URL to download open errors as CSV

> Returns a pre-signed S3 URL that streams all currently-open errors for a flow step as a CSV\
> file. The URL expires after approximately 15 minutes. The CSV always includes a header row,\
> even when the step has zero open errors.\
> \
> CSV columns: \`occurredAt\`, \`source\`, \`code\`, \`message\`, \`traceKey\`, \`exportDataURI\`,\
> \`importDataURI\`, \`oIndex\`, \`retryDataKey\`, \`errorId\`, \`legacyId\`, \`reqAndResKey\`, \`purgeAt\`,\
> \`tags\`, \`assignedTo\`, \`assignedBy\`, \`\_assignedToUserId\`.\
> \
> The signed URL requires no auth headers — do not attach your bearer token when fetching the CSV.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepSignedURLResponse":{"type":"object","description":"Pre-signed S3 URL for downloading error or retry data as a CSV file. The URL expires after\napproximately 15 minutes. Returned by the `signedURL` endpoints on errors, resolved errors,\nand retry data.","properties":{"signedURL":{"type":"string","format":"uri","description":"Pre-signed S3 URL that streams a CSV file when fetched with a plain GET (no auth headers\nneeded). Expires ~15 minutes after generation. The CSV always includes a header row, even\nwhen there are zero matching records."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/errors/signedURL":{"get":{"operationId":"getFlowStepErrorsSignedURL","tags":["Flows"],"summary":"Get a signed URL to download open errors as CSV","description":"Returns a pre-signed S3 URL that streams all currently-open errors for a flow step as a CSV\nfile. The URL expires after approximately 15 minutes. The CSV always includes a header row,\neven when the step has zero open errors.\n\nCSV columns: `occurredAt`, `source`, `code`, `message`, `traceKey`, `exportDataURI`,\n`importDataURI`, `oIndex`, `retryDataKey`, `errorId`, `legacyId`, `reqAndResKey`, `purgeAt`,\n`tags`, `assignedTo`, `assignedBy`, `_assignedToUserId`.\n\nThe signed URL requires no auth headers — do not attach your bearer token when fetching the CSV.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id — the step within the flow.","schema":{"type":"string","format":"objectId"}},{"name":"startAtErrorId","in":"query","required":false,"description":"Resume from this error id — errors with ids lexically before this value are excluded from\nthe CSV. Useful for incremental downloads.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-signed S3 URL for the errors CSV.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepSignedURLResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## List resolved errors on a flow step

> Returns one page of already-resolved errors for a flow step (same shape as the open-errors listing).\
> \
> Errors arrive here either because a user marked them resolved (\`PUT .../resolved\`) or because a\
> retry was submitted for them — a retry resolves its errors when it is submitted, whatever its\
> outcome. The platform retains resolved errors through the account's\
> retention window; use \`DELETE .../resolved\` to purge them earlier.\
> \
> \`resolvedBy\` distinguishes how each error was closed: \`auto\` means a system-initiated\
> auto-retry cleared it; a user ID means the error was resolved manually or via a\
> user-triggered retry.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepResolvedResponse":{"type":"object","description":"One page of resolved errors for a flow step. Resolved errors are retained for audit (and for\npotential un-resolving, though that's not exposed as an API operation) until either a user deletes\nthem via `DELETE .../resolved` or the purge window expires.","properties":{"resolved":{"type":"array","description":"Resolved error records on this page.","items":{"allOf":[{"$ref":"#/components/schemas/FlowStepError"},{"type":"object","description":"Fields added when an error transitions from open to resolved.","properties":{"resolvedAt":{"type":"string","format":"date-time","description":"When the error was marked resolved."},"resolvedBy":{"type":"string","description":"`\"auto\"` when the platform resolved it (a system-initiated retry, or a\nconnection-class error resolved at the end of a job), or the Mongo **user id** (not\nemail) of the user who resolved it — through `PUT .../resolved`, or by submitting a\nretry, which resolves its errors when it is submitted.\nCross-reference via `GET /v1/ashares/{_id}` to resolve the id to a profile."}}}]}},"nextPageURL":{"type":"string","description":"URL for the next page. **Omitted entirely** (not `null`) when there are no further pages."}}},"FlowStepError":{"type":"object","description":"One open-error record on a flow step. Errors accumulate per `(flow, step)` pair as the flow runs;\nthey remain \"open\" until a user marks them resolved (`PUT .../resolved`) or submits a retry for\nthem (`POST .../retry` resolves them at submission, whatever the retry's outcome).","properties":{"errorId":{"type":"string","description":"Platform-assigned id for the error. This is the identifier you feed to assign / resolve /\ndelete-resolved endpoints via the `errorIds` (or `errors`) body array."},"occurredAt":{"type":"string","format":"date-time","description":"When the error happened (ISO 8601, UTC)."},"source":{"type":"string","description":"Step stage or system the error came from, such as `application`, `connection`, a hook\n(`pre_save_page_hook`, `post_response_map_hook`) or a filter (`output_filter`).\n`application` covers the step's whole call to the external system, not only its answer:\nbesides errors the destination returned, it marks a request that never got an answer,\nsuch as a URL template that failed to render (`handlebars_template_parse_error`) or a\nrefused connection, so read `code` and `message` with it. `GET /v1/errors/filterMetadata`\nlists the source values the errors filter accepts."},"code":{"type":"string","description":"Error code. For HTTP-sourced errors this is the stringified HTTP status (`\"500\"`, `\"401\"`).\nFor platform-classified errors it's a symbolic code (e.g. `\"script_error\"`)."},"message":{"type":"string","description":"Human-readable message. Frequently a JSON string that the adaptor received as a response body.\nStored cut to 500 characters: a longer message keeps its first 497 characters followed by\n`...`. A template parse error (`handlebars_template_parse_error`) repeats the whole template\nbefore its parse detail, so in a long template the detail is cut off; invoking the import\n(`POST /v1/imports/{_id}/invoke`) with the record returns the full message."},"oIndex":{"type":"string","description":"Zero-based index of the offending record within its batch (page). Paired with `_flowJobId` this\npinpoints the record inside the run's execution log."},"_flowJobId":{"type":"string","format":"objectId","description":"Id of the flow-run job this error came from. Use with `GET /v1/jobs/{_id}` for run context."},"traceKey":{"type":"string","description":"Upstream export/record identifier that produced this error — correlates the error back to the\nsource record across the execution log. Populated on every error in practice; callers doing\nrecord-level triage join on this field."},"classification":{"type":"string","description":"Category the platform derives from the error's code, message, and source — read-only, never\nset by users; `intermittent` errors are retried automatically while the flow's\n`autoResolveMatchingTraceKeys` is on. Absent when nothing matched with confidence. The value\nset is the `classification` dimension of the errors filter metadata."},"classifiedBy":{"type":"string","description":"`auto` on every classified error; absent on unclassified ones."},"reqAndResKey":{"type":"string","description":"Opaque key for the stored HTTP request+response pair associated with this error. Pass to\n`GET /v1/flows/{_id}/{_stepId}/requests/{reqAndResKey}` to fetch the decoded HTTP detail. Absent\nwhen the error was not produced by an HTTP adaptor."},"retryDataKey":{"type":"string","description":"Opaque key for the per-record data snapshot captured at the moment of failure. Populated on\nrecord-level errors (imports, transforms) where a retry means re-running the record; absent on\nconnection-level failures. Pass to `POST /v1/flows/{_id}/{_stepId}/retry` (as `retryDataKeys[]`)\nto retry, or to `GET /v1/flows/{_id}/{_stepId}/{retryDataKey}/data` to inspect / mutate the\nsnapshot before retry."},"purgeAt":{"type":"string","description":"Epoch-milliseconds timestamp (as a string) when the error record is scheduled for automatic\ndeletion from the queue. Drives the 30-day retention window by default."},"retryAt":{"type":"string","format":"date-time","description":"Present while the platform is auto-retrying this `intermittent` error. On a first-occurrence\nerror it is stamped about a minute after `occurredAt` and is not the first attempt time (that\nruns roughly 30 minutes out); on the error a failed attempt opens, it is the next scheduled\nattempt. Absent once the attempts are exhausted and on errors that are not auto-retried."},"tags":{"type":["array","null"],"description":"Tag names currently attached to this error, or `null` when no tags are set. Stored as the\nhuman-readable `tag` value (e.g. `\"Investigating\"`), **not** the short `tagId` code used when\nwriting via `PUT /v1/flows/{_id}/{_stepId}/tags`. Resolve names ↔ codes via `GET /v1/tags`.","items":{"type":"string"}},"assignedTo":{"type":"string","description":"Display name of the user currently assigned to this error for triage when the email resolves\nto a known account user (e.g. `\"Jane Doe\"`). When the email does not match a known\nuser, the literal email string is stored instead. Set via\n`PUT /v1/flows/{_id}/{_stepId}/errors/assign`. Absent when no assignment has been made."},"assignedBy":{"type":"string","description":"Mongo user id of the user who made the assignment. Absent when no assignment has been made."},"_assignedToUserId":{"type":"string","format":"objectId","description":"Mongo user id of the assignee. Paired with `assignedTo` for callers that need the id directly."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/resolved":{"get":{"operationId":"listFlowStepResolvedErrors","tags":["Flows"],"summary":"List resolved errors on a flow step","description":"Returns one page of already-resolved errors for a flow step (same shape as the open-errors listing).\n\nErrors arrive here either because a user marked them resolved (`PUT .../resolved`) or because a\nretry was submitted for them — a retry resolves its errors when it is submitted, whatever its\noutcome. The platform retains resolved errors through the account's\nretention window; use `DELETE .../resolved` to purge them earlier.\n\n`resolvedBy` distinguishes how each error was closed: `auto` means a system-initiated\nauto-retry cleared it; a user ID means the error was resolved manually or via a\nuser-triggered retry.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"_flowJobId","in":"query","required":false,"description":"Only return resolved errors produced by this flow-run job. Must be paired with\n`resolvedAt_gte` — without it the request fails with 400 `invalid_flowjobid_param`.","schema":{"type":"string","format":"objectId"}},{"name":"occurredAt_gte","in":"query","required":false,"description":"Only return errors that originally occurred at or after this instant (inclusive). Bounds\n`occurredAt` (when the error happened), not `resolvedAt` (when it was closed).","schema":{"type":"string","format":"date-time"}},{"name":"occurredAt_lte","in":"query","required":false,"description":"Only return errors that originally occurred at or before this instant (inclusive).\nCombine with `occurredAt_gte` to bound when the errors happened.","schema":{"type":"string","format":"date-time"}},{"name":"resolvedAt_gte","in":"query","required":false,"description":"Only return errors resolved at or after this instant (inclusive). Required whenever\n`_flowJobId` is supplied; usable on its own to bound the window.","schema":{"type":"string","format":"date-time"}},{"name":"resolvedAt_lte","in":"query","required":false,"description":"Only return errors resolved at or before this instant (inclusive). Optional even when\nfiltering by `_flowJobId`; combine with `resolvedAt_gte` to select a window.","schema":{"type":"string","format":"date-time"}},{"name":"tags","in":"query","required":false,"explode":true,"description":"Only return resolved errors carrying at least one of the listed tags. Repeat the parameter\nonce per value (`?tags=ShHjr&tags=untagged`); values are the account's short `tagId` codes\nfrom `GET /v1/tags`, not the tag names shown in each error's `tags` array — unknown values\nfail with 400 `invalid_tagid_param`. The literal value `untagged` matches errors with no\ntags and can be mixed with real tag ids.","schema":{"type":"array","items":{"type":"string"}}},{"name":"resolvedBy","in":"query","required":false,"explode":true,"description":"Only return errors closed by the listed resolvers. Repeat the parameter once per value;\neach value is a Mongo user id (matching the `resolvedBy` field on user-resolved errors).\nThe literal value `auto` matches platform-auto-resolved errors and can be mixed with\nuser ids (`?resolvedBy=<userId>&resolvedBy=auto`). Unknown values are\nnot rejected — they simply match nothing.","schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"One page of resolved errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepResolvedResponse"}}}},"400":{"description":"Invalid filter parameters. `invalid_flowjobid_param` — `_flowJobId` was supplied without\n`resolvedAt_gte`. `invalid_ref` — `_flowJobId` is not a valid object id.\n`invalid_tagid_param` — a `tags` value is not a known tag id (or `untagged`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Mark open errors as resolved

> Moves a batch of currently-open errors to the resolved list. The underlying records are unchanged —\
> no retry happens; this is purely an administrative state change used to clear the open-errors queue\
> after a user has reviewed the failures and decided they're not actionable.\
> \
> To actually re-run the failed records, use \`POST .../retry\` instead. The request body field\
> is named \`errors\` (carrying error ids), not \`errorIds\`. To clear the whole open-error queue in one\
> call without listing ids, send \`selectAll: true\` with a \`lastErrorAt\` high-water mark instead of\
> \`errors\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepResolveRequest":{"type":"object","description":"Request body for `PUT /v1/flows/{_id}/{_stepId}/resolved`. Marks a batch of currently-open errors\nas resolved — they move from the `errors` list to the `resolved` list. Target the errors one of two\nways: list their ids in `errors`, or set `selectAll: true` with a `lastErrorAt` high-water mark to\nresolve every open error on the step without enumerating ids. The id field is named `errors` (not\n`errorIds`) for historical reasons; it carries error ids.","properties":{"errors":{"type":"array","description":"Ids of open errors to mark resolved. Obtain from `GET /v1/flows/{_id}/{_stepId}/errors` → each\nentry's `errorId`. Required unless `selectAll` is true.","minItems":1,"items":{"type":"string"}},"selectAll":{"type":"boolean","description":"When true, resolves every open error on the step in a single call, no matter how many, instead\nof an enumerated `errors` list — omit `errors` and supply `lastErrorAt` to bound the batch."},"lastErrorAt":{"type":"string","format":"date-time","description":"Inclusive high-water mark for `selectAll`: errors whose `occurredAt` is after this instant are\nnot resolved, so failures that arrive after you trigger the bulk resolve stay open. Set it to\nthe step's most recent error timestamp — the `lastErrorAt` returned by\n`GET /v1/flows/{_id}/errors`. Required when `selectAll` is true (otherwise the request fails\nwith 422 `lastErrorAt is required when selectAll is true.`)."}},"if":{"properties":{"selectAll":{"const":true}},"required":["selectAll"]},"then":{"required":["selectAll","lastErrorAt"]},"else":{"required":["errors"]}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/resolved":{"put":{"operationId":"resolveFlowStepErrors","tags":["Flows"],"summary":"Mark open errors as resolved","description":"Moves a batch of currently-open errors to the resolved list. The underlying records are unchanged —\nno retry happens; this is purely an administrative state change used to clear the open-errors queue\nafter a user has reviewed the failures and decided they're not actionable.\n\nTo actually re-run the failed records, use `POST .../retry` instead. The request body field\nis named `errors` (carrying error ids), not `errorIds`. To clear the whole open-error queue in one\ncall without listing ids, send `selectAll: true` with a `lastErrorAt` high-water mark instead of\n`errors`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepResolveRequest"}}}},"responses":{"204":{"description":"Errors resolved (no body)."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"`invalid_request` — `selectAll` was true but `lastErrorAt` was omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Permanently delete resolved errors

> Permanently removes resolved error records from the account. Use when the retention window hasn't\
> expired yet but you want to clear out the resolved list (e.g. after a one-time cleanup pass).\
> \
> Only resolved errors can be deleted through this endpoint — open errors must be resolved first.\
> This is destructive: the records and their associated HTTP request/response captures are\
> permanently removed. The request body field is named \`errors\` (carrying error ids). To clear the\
> whole resolved list without listing ids, send \`selectAll: true\` with a \`lastErrorAt\` high-water\
> mark instead of \`errors\` — note that here \`lastErrorAt\` bounds each record's \`resolvedAt\`, not\
> \`occurredAt\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepResolvedDeleteRequest":{"type":"object","description":"Request body for `DELETE /v1/flows/{_id}/{_stepId}/resolved`. Permanently deletes resolved errors\nfrom the account. Target the errors one of two ways: list their ids in `errors`, or set\n`selectAll: true` with a `lastErrorAt` high-water mark to delete every resolved error on the step\nwithout enumerating ids. The id field is named `errors` (carries error ids) — this matches the\nshape used by the resolve PUT.","properties":{"errors":{"type":"array","description":"Ids of resolved errors to delete. Obtain from `GET /v1/flows/{_id}/{_stepId}/resolved` → each\nentry's `errorId`. Required unless `selectAll` is true.","minItems":1,"items":{"type":"string"}},"selectAll":{"type":"boolean","description":"When true, deletes every resolved error on the step instead of an enumerated `errors` list —\nomit `errors` and supply `lastErrorAt` to bound the batch."},"lastErrorAt":{"type":"string","format":"date-time","description":"Inclusive high-water mark for `selectAll`. Unlike resolve/retry (which bound on `occurredAt`),\nthis bounds each resolved record's `resolvedAt`: records resolved after this instant are not\ndeleted. Required when `selectAll` is true (otherwise the request fails with 422\n`lastErrorAt is required when selectAll is true.`)."}},"if":{"properties":{"selectAll":{"const":true}},"required":["selectAll"]},"then":{"required":["selectAll","lastErrorAt"]},"else":{"required":["errors"]}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/resolved":{"delete":{"operationId":"deleteFlowStepResolvedErrors","tags":["Flows"],"summary":"Permanently delete resolved errors","description":"Permanently removes resolved error records from the account. Use when the retention window hasn't\nexpired yet but you want to clear out the resolved list (e.g. after a one-time cleanup pass).\n\nOnly resolved errors can be deleted through this endpoint — open errors must be resolved first.\nThis is destructive: the records and their associated HTTP request/response captures are\npermanently removed. The request body field is named `errors` (carrying error ids). To clear the\nwhole resolved list without listing ids, send `selectAll: true` with a `lastErrorAt` high-water\nmark instead of `errors` — note that here `lastErrorAt` bounds each record's `resolvedAt`, not\n`occurredAt`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepResolvedDeleteRequest"}}}},"responses":{"204":{"description":"Resolved errors deleted (no body)."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"`invalid_request` — `selectAll` was true but `lastErrorAt` was omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get a signed URL to download resolved errors as CSV

> Returns a pre-signed S3 URL that streams all resolved errors for a flow step as a CSV file.\
> The URL expires after approximately 15 minutes. The CSV always includes a header row, even\
> when there are zero resolved errors.\
> \
> The CSV includes the same columns as the open-errors signed URL, plus two prepended columns:\
> \`resolvedAt\` and \`resolvedBy\`.\
> \
> Full CSV columns: \`resolvedAt\`, \`resolvedBy\`, \`occurredAt\`, \`source\`, \`code\`, \`message\`,\
> \`traceKey\`, \`exportDataURI\`, \`importDataURI\`, \`oIndex\`, \`retryDataKey\`, \`errorId\`, \`legacyId\`,\
> \`reqAndResKey\`, \`purgeAt\`, \`tags\`, \`assignedTo\`, \`assignedBy\`, \`\_assignedToUserId\`.\
> \
> For currently-open errors, use \`GET .../errors/signedURL\` instead.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepSignedURLResponse":{"type":"object","description":"Pre-signed S3 URL for downloading error or retry data as a CSV file. The URL expires after\napproximately 15 minutes. Returned by the `signedURL` endpoints on errors, resolved errors,\nand retry data.","properties":{"signedURL":{"type":"string","format":"uri","description":"Pre-signed S3 URL that streams a CSV file when fetched with a plain GET (no auth headers\nneeded). Expires ~15 minutes after generation. The CSV always includes a header row, even\nwhen there are zero matching records."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/resolved/signedURL":{"get":{"operationId":"getFlowStepResolvedSignedURL","tags":["Flows"],"summary":"Get a signed URL to download resolved errors as CSV","description":"Returns a pre-signed S3 URL that streams all resolved errors for a flow step as a CSV file.\nThe URL expires after approximately 15 minutes. The CSV always includes a header row, even\nwhen there are zero resolved errors.\n\nThe CSV includes the same columns as the open-errors signed URL, plus two prepended columns:\n`resolvedAt` and `resolvedBy`.\n\nFull CSV columns: `resolvedAt`, `resolvedBy`, `occurredAt`, `source`, `code`, `message`,\n`traceKey`, `exportDataURI`, `importDataURI`, `oIndex`, `retryDataKey`, `errorId`, `legacyId`,\n`reqAndResKey`, `purgeAt`, `tags`, `assignedTo`, `assignedBy`, `_assignedToUserId`.\n\nFor currently-open errors, use `GET .../errors/signedURL` instead.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"startAtErrorId","in":"query","required":false,"description":"Resume from this error id — errors with ids lexically before this value are excluded from\nthe CSV.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-signed S3 URL for the resolved errors CSV.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepSignedURLResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Retry errored records

> Re-runs the per-record data snapshots captured when the listed errors occurred. Submitting the\
> retry resolves the listed errors at once, before the retry job runs and whatever it does; a record\
> that fails again comes back as a new open error.\
> \
> Only errors that carry a \`retryDataKey\` can be retried — typically these are record-level errors\
> from imports or transforms. Connection-level errors (\`classification: connection\`) don't have a\
> \`retryDataKey\`; to recover from those, re-run the whole flow after fixing the connection.\
> \
> \*\*Response behavior splits on whether anything matched:\*\*\
> \- At least one record matched — a supplied \`retryDataKey\`, or (in \`selectAll\` mode) a retriable\
> &#x20; open error on or before \`lastErrorAt\` → \*\*200\*\* with a \`type: "retry"\` Job record (the queued\
> &#x20; retry job; poll it via \`GET /v1/jobs/{\_id}\`). The matched errors move from \`GET .../errors\` to\
> &#x20; \`/resolved\` as the job is queued, with \`resolvedBy\` set to the user who submitted the retry.\
> &#x20; System-initiated auto-retries set \`resolvedBy\` to \`"auto"\` instead.\
> \- Nothing matched → \*\*204\*\* silent no-op. There is no per-key validation: the endpoint does not\
> &#x20; 400 on bogus keys; callers must poll \`GET .../errors\` to confirm any change.\
> \
> \*\*Retry outcome semantics.\*\* A record that fails again becomes a \*\*new\*\* open error with a new\
> \`errorId\`, the same \`retryDataKey\` and \`traceKey\`, and the retry job's id as \`\_flowJobId\`; the\
> original stays resolved. Reconcile the "before" and "after" error lists by \`retryDataKey\`, not\
> \`errorId\`.\
> \
> To modify a record before retrying, call \`GET .../{ retryDataKey}/data\`, mutate the payload,\
> \`PUT\` it back, then call this endpoint. Retried records go through the same page-processor\
> pipeline as new records with no ordering guarantees. To retry the whole open-error queue without\
> listing keys, send \`selectAll: true\` with a \`lastErrorAt\` high-water mark instead of\
> \`retryDataKeys\` — one call retries every matching error, no matter how many (errors without a\
> \`retryDataKey\` are skipped).

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRetryRequest":{"type":"object","description":"Request body for `POST /v1/flows/{_id}/{_stepId}/retry`. Re-runs the per-record data snapshot\ncaptured at the moment each error occurred. Submitting it resolves the targeted errors at once; a\nrecord that fails again comes back as a new open error.\nTarget the records one of two ways: list their snapshot keys in `retryDataKeys`, or set\n`selectAll: true` with a `lastErrorAt` high-water mark to retry every retriable open error on the\nstep without enumerating keys.","properties":{"retryDataKeys":{"type":"array","description":"Opaque per-error snapshot keys. Obtain from `GET /v1/flows/{_id}/{_stepId}/errors` →\n`retryDataKey` on each entry that has one. Errors without a `retryDataKey` (typically\nconnection-level failures) cannot be retried via this endpoint — rerun the whole flow instead.\nRequired unless `selectAll` is true.","minItems":1,"items":{"type":"string"}},"selectAll":{"type":"boolean","description":"When true, retries every retriable open error on the step in a single call, no matter how many,\ninstead of an enumerated `retryDataKeys` list — omit `retryDataKeys` and supply `lastErrorAt`\nto bound the batch. Open errors without a `retryDataKey` are skipped."},"lastErrorAt":{"type":"string","format":"date-time","description":"Inclusive high-water mark for `selectAll`: errors whose `occurredAt` is after this instant are\nnot retried, so failures that arrive after you trigger the bulk retry stay open. Set it to the\nstep's most recent error timestamp — the `lastErrorAt` returned by `GET /v1/flows/{_id}/errors`.\nRequired when `selectAll` is true (otherwise the request fails with 422\n`lastErrorAt is required when selectAll is true.`)."}},"if":{"properties":{"selectAll":{"const":true}},"required":["selectAll"]},"then":{"required":["selectAll","lastErrorAt"]},"else":{"required":["retryDataKeys"]}},"Job":{"type":"object","required":["_id","type","status","createdAt","lastModified"],"description":"A job represents one execution of a flow/export/import (or a retry) in integrator.io.\nJobs are read-only records created by the platform when executions occur.\n\nParent jobs (`type: flow`) carry aggregate counters; child jobs (`type: export` or `import`)\ncarry per-step counters -- do not sum both to avoid double-counting. `_exportId` on a parent\nflow job references the page-generator export, not all exports in the flow.\n","allOf":[{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"type":{"type":"string","readOnly":true,"description":"Job type.","enum":["export","import","flow","retry","bulk_retry"]},"status":{"type":"string","readOnly":true,"description":"Current job status.","enum":["queued","running","retrying","completed","failed","canceled","canceling"]},"_integrationId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration id this job belongs to (if applicable)."},"_flowId":{"type":"string","format":"objectId","readOnly":true,"description":"Flow id this job belongs to (if applicable)."},"_exportId":{"type":"string","format":"objectId","readOnly":true,"description":"Export id. Present on child export jobs and also on parent flow\njobs (where it references the first page-generator export)."},"_importId":{"type":"string","format":"objectId","readOnly":true,"description":"Import id for import child jobs (if applicable)."},"_expOrImpId":{"type":"string","format":"objectId","readOnly":true,"description":"The export or import resource ID for this child job. Present on child\njobs (`type: export` or `type: import`) — check `type` to determine\nwhether this references an export or import resource."},"_retryOfJobId":{"type":"string","format":"objectId","readOnly":true,"description":"If this is a retry job, the original job id being retried."},"_flowJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent flow job id (for child jobs)."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owner user id for the job."},"_parentJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent job id (used for branched flows / hierarchy)."},"_bulkJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Bulk retry parent job id (if applicable)."},"startedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When execution started."},"endedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When execution ended."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When errors for the job were fully resolved (if applicable)."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Last time the job executed work (may differ from createdAt/startedAt)."},"purgeAt":{"type":"string","format":"date-time","readOnly":true,"description":"When the job should be purged from primary storage."},"clickhousePurgeAt":{"type":"string","format":"date-time","readOnly":true,"description":"When the job's analytics data expires."},"triggeredBy":{"type":"string","readOnly":true,"description":"What started the run. On a `flow` job: `system` for a scheduled run, the `_id` of\nthe user who ran the flow, or the `_id` of the upstream flow whose `_runNextFlowIds`\nchained into this one; absent on event-driven runs (webhook, real-time listener, and\nstream page generators), which the inbound event starts. On a `retry` job: `auto`\nfor the platform's automatic intermittent-error retry, otherwise the `_id` of the\nuser who submitted the retry. Absent on `export` and `import` child jobs — the\nparent flow job carries it."},"canceledBy":{"type":"string","readOnly":true,"description":"Who canceled the run: the `_id` of the user who requested the cancel, or `system` for\nevery platform-initiated cancel — stuck-run recovery after a worker exit or crash or\nwhen a run stops making progress, stale-run cleanup, a scheduler that could not\nre-queue the run, and the cancels that follow deleting the flow or replacing one of\nits connections. The record does not say which of these it was."},"flowExecutionGroupId":{"type":"string","readOnly":true,"description":"Groups multiple related jobs for a single flow execution."},"numError":{"type":"integer","readOnly":true,"description":"Total number of errors produced by the job (including resolved ones).\nUse `numOpenError` for the count of currently unresolved errors.\nOn a parent flow job this is the sum across every step; on a child job it is that step's count.\n"},"numOpenError":{"type":"integer","readOnly":true,"description":"Number of unresolved errors (equivalent to `numError - numResolved`).\nThis is the value dashboards surface as \"errors needing attention.\"\n"},"numResolved":{"type":"integer","readOnly":true,"description":"Number of resolved errors."},"numResolvedByAdaptor":{"type":"integer","readOnly":true,"description":"Number of errors resolved by the adaptor."},"numSuccess":{"type":"integer","readOnly":true,"description":"Number of records processed successfully. On a parent flow job (`type: flow`) this is the\nsum across every step in the run, so one record that passes through an export and an import\ncounts twice. On a child job (`type: export` or `import`) it is that step's count alone.\nFor per-step counts, read the run with `GET /v1/jobs/{_id}/family` or list its children with\n`GET /v1/jobs?_flowJobId={_id}&type=import`."},"numIgnore":{"type":"integer","readOnly":true,"description":"Number of records skipped: by a filter, by an import's ignore-existing or ignore-missing\nrule, by an import's preMap hook that returned no data for the record, or by a lookup step's\ninput filter (the record continues without the lookup's data). Records an import's filter skips count in that import's child job; records an export's\noutput filter drops count in the export's child job, whose `numSuccess` then counts only the\nrecords that passed (an export that read 6 records and dropped 3 reads `numSuccess` 3,\n`numIgnore` 3; live-verified 2026-10-22). Filtered records raise no error.\nSummed across steps on a parent flow job; per step on a child job."},"numExport":{"type":"integer","readOnly":true,"description":"Legacy field used by retry logic. May be deprecated.\n"},"numPagesGenerated":{"type":"integer","readOnly":true,"description":"Number of pages generated by an export/page generator."},"doneExporting":{"type":"boolean","readOnly":true,"description":"When true, all export pages have been generated."},"numPagesProcessed":{"type":"integer","readOnly":true,"description":"Number of pages processed by downstream steps: imports and lookup steps. A source export's\nchild job reads 0, a lookup step's and an import's count the pages they processed, and a\nparent flow job sums its children."},"oIndex":{"type":"integer","readOnly":true,"description":"Branch/router index for branched flows (if applicable)."},"retriable":{"type":"boolean","readOnly":true,"description":"When true, this job is eligible for retry."},"files":{"type":"array","readOnly":true,"description":"Files produced by the job (may be empty).","items":{"$ref":"#/components/schemas/JobFileRef"}},"logs":{"type":"array","readOnly":true,"description":"Log artifacts associated with the job (may be empty).","items":{"$ref":"#/components/schemas/JobLogRef"}},"errorFile":{"description":"Error file artifact (if any).","allOf":[{"$ref":"#/components/schemas/JobErrorFileRef"},{"description":"Error file artifact (if any)."}]},"logMode":{"type":"string","readOnly":true,"description":"Execution-logging level the run captured at, resolved from the flow's `logging.mode`,\nan open debug window (`logging.debugUntil`) and the account-level logging preference:\n`basic`, `detailed`, or `debug` while a debug window is open. Not set on a run that\ncaptured no execution logs, such as one that ran while the account-level preference\nwas off."},"__lastPageGeneratorJob":{"type":"boolean","readOnly":true,"description":"When true, indicates the last page-generator job in the sequence. Internal use only."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"JobFileRef":{"type":"object","description":"Reference to a file produced by a job.","properties":{"id":{"type":"string","description":"File id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["netsuite","s3"]},"name":{"type":"string","description":"Display name for the file (if available)."}}},"JobLogRef":{"type":"object","description":"Reference to a job log artifact.","properties":{"id":{"type":"string","description":"Log id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["netsuite"]}}},"JobErrorFileRef":{"type":"object","description":"Reference to an error file produced by a job.","properties":{"id":{"type":"string","description":"Error file id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["s3"]}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/retry":{"post":{"operationId":"retryFlowStepErrors","tags":["Flows"],"summary":"Retry errored records","description":"Re-runs the per-record data snapshots captured when the listed errors occurred. Submitting the\nretry resolves the listed errors at once, before the retry job runs and whatever it does; a record\nthat fails again comes back as a new open error.\n\nOnly errors that carry a `retryDataKey` can be retried — typically these are record-level errors\nfrom imports or transforms. Connection-level errors (`classification: connection`) don't have a\n`retryDataKey`; to recover from those, re-run the whole flow after fixing the connection.\n\n**Response behavior splits on whether anything matched:**\n- At least one record matched — a supplied `retryDataKey`, or (in `selectAll` mode) a retriable\n  open error on or before `lastErrorAt` → **200** with a `type: \"retry\"` Job record (the queued\n  retry job; poll it via `GET /v1/jobs/{_id}`). The matched errors move from `GET .../errors` to\n  `/resolved` as the job is queued, with `resolvedBy` set to the user who submitted the retry.\n  System-initiated auto-retries set `resolvedBy` to `\"auto\"` instead.\n- Nothing matched → **204** silent no-op. There is no per-key validation: the endpoint does not\n  400 on bogus keys; callers must poll `GET .../errors` to confirm any change.\n\n**Retry outcome semantics.** A record that fails again becomes a **new** open error with a new\n`errorId`, the same `retryDataKey` and `traceKey`, and the retry job's id as `_flowJobId`; the\noriginal stays resolved. Reconcile the \"before\" and \"after\" error lists by `retryDataKey`, not\n`errorId`.\n\nTo modify a record before retrying, call `GET .../{ retryDataKey}/data`, mutate the payload,\n`PUT` it back, then call this endpoint. Retried records go through the same page-processor\npipeline as new records with no ordering guarantees. To retry the whole open-error queue without\nlisting keys, send `selectAll: true` with a `lastErrorAt` high-water mark instead of\n`retryDataKeys` — one call retries every matching error, no matter how many (errors without a\n`retryDataKey` are skipped).","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRetryRequest"}}}},"responses":{"200":{"description":"Retry job queued. Body is the queued `type: \"retry\"` job record; poll it via\n`GET /v1/jobs/{_id}` to observe the retry's outcome.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Job"},{"type":"object","properties":{"retryErrorCount":{"type":"integer","readOnly":true,"description":"Number of errors selected for this retry job — whether\nenumerated explicitly or matched by `selectAll` filters.\nSpecific to this endpoint's response; not stored on the\njob record."}}}]}}}},"204":{"description":"Nothing was retried — silent no-op. In enumerated mode, none of the supplied `retryDataKeys`\nmatched a stored snapshot; in `selectAll` mode, no retriable open error occurred on or before\n`lastErrorAt`. Poll `GET .../errors` to confirm state."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"Request could not be processed. `inactive_flow` — the flow is disabled; enable it before\nretrying. `invalid_request` — `selectAll` was true but `lastErrorAt` was omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Retry errored records with exponential back-off

> Re-runs errored record snapshots using an exponential decay (back-off) strategy. Behaves like\
> \`POST .../retry\` but schedules retries with increasing delays between attempts, reducing load\
> on the target system during transient outages.\
> \
> \*\*Response behavior splits on whether anything matched:\*\*\
> \- At least one record matched — a supplied \`retryDataKey\`, or (in \`selectAll\` mode) a retriable\
> &#x20; open error on or before \`lastErrorAt\` → \*\*200\*\* with a full \`type: "retry"\` Job record.\
> \- Nothing matched → \*\*204\*\* silent no-op.\
> \
> The flow must be enabled (not disabled).\
> \
> Prefer this over \`POST .../retry\` when errors are caused by rate-limiting or transient\
> target-system issues. Only errors with a \`retryDataKey\` can be retried — connection-level\
> errors lack one and require a full flow rerun to recover. To retry the whole open-error queue\
> without listing keys, send \`selectAll: true\` with a \`lastErrorAt\` high-water mark instead of\
> \`retryDataKeys\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRetryExponentialRequest":{"type":"object","description":"Request body for `POST /v1/flows/{_id}/{_stepId}/retry_with_exponential_decay`. Retries errored\nrecords using an exponential back-off strategy. Returns a Job object when at least one key matched,\nor 204 if none matched. Target the records one of two ways: list their snapshot keys in\n`retryDataKeys`, or set `selectAll: true` with a `lastErrorAt` high-water mark to retry every\nretriable open error on the step without enumerating keys.","properties":{"retryDataKeys":{"type":"array","description":"Opaque per-error snapshot keys. Same format as `POST .../retry`. Only errors that carry a\n`retryDataKey` can be retried. Required unless `selectAll` is true.","minItems":1,"items":{"type":"string"}},"selectAll":{"type":"boolean","description":"When true, retries every retriable open error on the step in a single call, no matter how many,\ninstead of an enumerated `retryDataKeys` list — omit `retryDataKeys` and supply `lastErrorAt`\nto bound the batch. Open errors without a `retryDataKey` are skipped."},"lastErrorAt":{"type":"string","format":"date-time","description":"Inclusive high-water mark for `selectAll`: errors whose `occurredAt` is after this instant are\nnot retried. Set it to the step's most recent error timestamp — the `lastErrorAt` returned by\n`GET /v1/flows/{_id}/errors`. Required when `selectAll` is true (otherwise the request fails\nwith 422 `lastErrorAt is required when selectAll is true.`)."}},"if":{"properties":{"selectAll":{"const":true}},"required":["selectAll"]},"then":{"required":["selectAll","lastErrorAt"]},"else":{"required":["retryDataKeys"]}},"Job":{"type":"object","required":["_id","type","status","createdAt","lastModified"],"description":"A job represents one execution of a flow/export/import (or a retry) in integrator.io.\nJobs are read-only records created by the platform when executions occur.\n\nParent jobs (`type: flow`) carry aggregate counters; child jobs (`type: export` or `import`)\ncarry per-step counters -- do not sum both to avoid double-counting. `_exportId` on a parent\nflow job references the page-generator export, not all exports in the flow.\n","allOf":[{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"type":{"type":"string","readOnly":true,"description":"Job type.","enum":["export","import","flow","retry","bulk_retry"]},"status":{"type":"string","readOnly":true,"description":"Current job status.","enum":["queued","running","retrying","completed","failed","canceled","canceling"]},"_integrationId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration id this job belongs to (if applicable)."},"_flowId":{"type":"string","format":"objectId","readOnly":true,"description":"Flow id this job belongs to (if applicable)."},"_exportId":{"type":"string","format":"objectId","readOnly":true,"description":"Export id. Present on child export jobs and also on parent flow\njobs (where it references the first page-generator export)."},"_importId":{"type":"string","format":"objectId","readOnly":true,"description":"Import id for import child jobs (if applicable)."},"_expOrImpId":{"type":"string","format":"objectId","readOnly":true,"description":"The export or import resource ID for this child job. Present on child\njobs (`type: export` or `type: import`) — check `type` to determine\nwhether this references an export or import resource."},"_retryOfJobId":{"type":"string","format":"objectId","readOnly":true,"description":"If this is a retry job, the original job id being retried."},"_flowJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent flow job id (for child jobs)."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owner user id for the job."},"_parentJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent job id (used for branched flows / hierarchy)."},"_bulkJobId":{"type":"string","format":"objectId","readOnly":true,"description":"Bulk retry parent job id (if applicable)."},"startedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When execution started."},"endedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When execution ended."},"resolvedAt":{"type":"string","format":"date-time","readOnly":true,"description":"When errors for the job were fully resolved (if applicable)."},"lastExecutedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Last time the job executed work (may differ from createdAt/startedAt)."},"purgeAt":{"type":"string","format":"date-time","readOnly":true,"description":"When the job should be purged from primary storage."},"clickhousePurgeAt":{"type":"string","format":"date-time","readOnly":true,"description":"When the job's analytics data expires."},"triggeredBy":{"type":"string","readOnly":true,"description":"What started the run. On a `flow` job: `system` for a scheduled run, the `_id` of\nthe user who ran the flow, or the `_id` of the upstream flow whose `_runNextFlowIds`\nchained into this one; absent on event-driven runs (webhook, real-time listener, and\nstream page generators), which the inbound event starts. On a `retry` job: `auto`\nfor the platform's automatic intermittent-error retry, otherwise the `_id` of the\nuser who submitted the retry. Absent on `export` and `import` child jobs — the\nparent flow job carries it."},"canceledBy":{"type":"string","readOnly":true,"description":"Who canceled the run: the `_id` of the user who requested the cancel, or `system` for\nevery platform-initiated cancel — stuck-run recovery after a worker exit or crash or\nwhen a run stops making progress, stale-run cleanup, a scheduler that could not\nre-queue the run, and the cancels that follow deleting the flow or replacing one of\nits connections. The record does not say which of these it was."},"flowExecutionGroupId":{"type":"string","readOnly":true,"description":"Groups multiple related jobs for a single flow execution."},"numError":{"type":"integer","readOnly":true,"description":"Total number of errors produced by the job (including resolved ones).\nUse `numOpenError` for the count of currently unresolved errors.\nOn a parent flow job this is the sum across every step; on a child job it is that step's count.\n"},"numOpenError":{"type":"integer","readOnly":true,"description":"Number of unresolved errors (equivalent to `numError - numResolved`).\nThis is the value dashboards surface as \"errors needing attention.\"\n"},"numResolved":{"type":"integer","readOnly":true,"description":"Number of resolved errors."},"numResolvedByAdaptor":{"type":"integer","readOnly":true,"description":"Number of errors resolved by the adaptor."},"numSuccess":{"type":"integer","readOnly":true,"description":"Number of records processed successfully. On a parent flow job (`type: flow`) this is the\nsum across every step in the run, so one record that passes through an export and an import\ncounts twice. On a child job (`type: export` or `import`) it is that step's count alone.\nFor per-step counts, read the run with `GET /v1/jobs/{_id}/family` or list its children with\n`GET /v1/jobs?_flowJobId={_id}&type=import`."},"numIgnore":{"type":"integer","readOnly":true,"description":"Number of records skipped: by a filter, by an import's ignore-existing or ignore-missing\nrule, by an import's preMap hook that returned no data for the record, or by a lookup step's\ninput filter (the record continues without the lookup's data). Records an import's filter skips count in that import's child job; records an export's\noutput filter drops count in the export's child job, whose `numSuccess` then counts only the\nrecords that passed (an export that read 6 records and dropped 3 reads `numSuccess` 3,\n`numIgnore` 3; live-verified 2026-10-22). Filtered records raise no error.\nSummed across steps on a parent flow job; per step on a child job."},"numExport":{"type":"integer","readOnly":true,"description":"Legacy field used by retry logic. May be deprecated.\n"},"numPagesGenerated":{"type":"integer","readOnly":true,"description":"Number of pages generated by an export/page generator."},"doneExporting":{"type":"boolean","readOnly":true,"description":"When true, all export pages have been generated."},"numPagesProcessed":{"type":"integer","readOnly":true,"description":"Number of pages processed by downstream steps: imports and lookup steps. A source export's\nchild job reads 0, a lookup step's and an import's count the pages they processed, and a\nparent flow job sums its children."},"oIndex":{"type":"integer","readOnly":true,"description":"Branch/router index for branched flows (if applicable)."},"retriable":{"type":"boolean","readOnly":true,"description":"When true, this job is eligible for retry."},"files":{"type":"array","readOnly":true,"description":"Files produced by the job (may be empty).","items":{"$ref":"#/components/schemas/JobFileRef"}},"logs":{"type":"array","readOnly":true,"description":"Log artifacts associated with the job (may be empty).","items":{"$ref":"#/components/schemas/JobLogRef"}},"errorFile":{"description":"Error file artifact (if any).","allOf":[{"$ref":"#/components/schemas/JobErrorFileRef"},{"description":"Error file artifact (if any)."}]},"logMode":{"type":"string","readOnly":true,"description":"Execution-logging level the run captured at, resolved from the flow's `logging.mode`,\nan open debug window (`logging.debugUntil`) and the account-level logging preference:\n`basic`, `detailed`, or `debug` while a debug window is open. Not set on a run that\ncaptured no execution logs, such as one that ran while the account-level preference\nwas off."},"__lastPageGeneratorJob":{"type":"boolean","readOnly":true,"description":"When true, indicates the last page-generator job in the sequence. Internal use only."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"JobFileRef":{"type":"object","description":"Reference to a file produced by a job.","properties":{"id":{"type":"string","description":"File id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["netsuite","s3"]},"name":{"type":"string","description":"Display name for the file (if available)."}}},"JobLogRef":{"type":"object","description":"Reference to a job log artifact.","properties":{"id":{"type":"string","description":"Log id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["netsuite"]}}},"JobErrorFileRef":{"type":"object","description":"Reference to an error file produced by a job.","properties":{"id":{"type":"string","description":"Error file id in the underlying storage provider."},"host":{"type":"string","description":"Storage host/provider.","enum":["s3"]}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/retry_with_exponential_decay":{"post":{"operationId":"retryFlowStepErrorsWithExponentialDecay","tags":["Flows"],"summary":"Retry errored records with exponential back-off","description":"Re-runs errored record snapshots using an exponential decay (back-off) strategy. Behaves like\n`POST .../retry` but schedules retries with increasing delays between attempts, reducing load\non the target system during transient outages.\n\n**Response behavior splits on whether anything matched:**\n- At least one record matched — a supplied `retryDataKey`, or (in `selectAll` mode) a retriable\n  open error on or before `lastErrorAt` → **200** with a full `type: \"retry\"` Job record.\n- Nothing matched → **204** silent no-op.\n\nThe flow must be enabled (not disabled).\n\nPrefer this over `POST .../retry` when errors are caused by rate-limiting or transient\ntarget-system issues. Only errors with a `retryDataKey` can be retried — connection-level\nerrors lack one and require a full flow rerun to recover. To retry the whole open-error queue\nwithout listing keys, send `selectAll: true` with a `lastErrorAt` high-water mark instead of\n`retryDataKeys`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRetryExponentialRequest"}}}},"responses":{"200":{"description":"Retry job queued with exponential back-off. Body is the queued `type: \"retry\"` job record;\npoll it via `GET /v1/jobs/{_id}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"204":{"description":"Nothing was retried — silent no-op. In enumerated mode, none of the supplied `retryDataKeys`\nmatched a stored snapshot; in `selectAll` mode, no retriable open error occurred on or before\n`lastErrorAt`."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"Request could not be processed. `inactive_flow` — the flow is disabled; enable it before\nretrying. `invalid_request` — `selectAll` was true but `lastErrorAt` was omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get the stored retry-data snapshot for an error

> Returns the per-record snapshot the runtime captured at the moment of failure — the shape that\
> \`POST .../retry\` re-feeds into the flow pipeline. The response is an envelope: \`data\` carries the\
> adaptor-specific record payload; surrounding fields (\`stage\`, \`pgExportId\`, \`oneToMany\`,\
> \`pathToMany\`, \`childIndex\`, \`traceKey\`) identify where in the pipeline the record was when it\
> failed and how it's structured.\
> \
> The \`data\` field is the record as it reached the failing step — on an HTTP import, before the\
> import's mappings, not the request the import sent. Use \`PUT .../{retryDataKey}/data\` to mutate\
> the snapshot before retrying. Only errors with a \`retryDataKey\` expose this endpoint;\
> connection-class errors are rejected with \`no\_retrydata\_found\`. The \`stage\` field indicates\
> where the retry will resume: \`page\_processor\_import\` re-runs the import (most common),\
> \`page\_generator\` means the error was upstream of the processor.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRetryData":{"type":"object","description":"Envelope around a per-record snapshot captured at the moment an error occurred. Returned by\n`GET /v1/flows/{_id}/{_stepId}/{retryDataKey}/data` and accepted (full-replace) by the PUT on the\nsame path.\n\nThe `data` field carries the record as it reached the failing step, which a retry runs through\nthat step again — its shape is adaptor-specific. The surrounding fields identify where in the\npipeline the failure happened and how the record was structured.","properties":{"retryDataKey":{"type":"string","description":"Echoes the path parameter."},"data":{"description":"The record as it reached the step. On an HTTP import it is the incoming record, before the\nimport's mappings — not the request body the import sent or the response it got back — and a\nretry maps it again with the import's current mappings, so a mapping fix reaches the retried\nrecord. Shape varies by adaptor.","additionalProperties":true},"stage":{"type":"string","description":"Pipeline stage where the record was when the error occurred."},"pgExportId":{"type":"string","format":"objectId","description":"Id of the page-generator export that originated this record."},"oneToMany":{"type":"boolean","description":"Whether the stored record represents a one-to-many expansion. When `true`, `childIndex` and\n`pathToMany` locate the specific sub-record inside the parent payload."},"pathToMany":{"type":["string","null"],"description":"JSON-path / dot-path into the parent payload naming the array of sub-records. Null on one-to-one records."},"childIndex":{"type":["integer","null"],"description":"Zero-based index into the `pathToMany` array when `oneToMany: true`. Null on one-to-one records."},"traceKey":{"type":["string","null"],"description":"Trace identifier for cross-bubble stitching in execution logs. Populated when the source export\nhas a `traceKeyTemplate` configured."},"adaptorResponse":{"type":"object","additionalProperties":true,"description":"Adaptor-level response envelope captured alongside the record payload. Present on failures\nreturned by an HTTP or import adaptor; carries fields like `data[]`, `errors[]`,\n`subGroupIdMapForSuccess`, `resultRecordIds`, `dataURIs`, `groupId`, `recordId`,\nand `ignoredResults`. Treat the shape as opaque — it varies by adaptor — and pass it through\nunchanged when PUT-ing the envelope back."}},"required":["retryDataKey","data","stage","oneToMany"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/{retryDataKey}/data":{"get":{"operationId":"getFlowStepErrorData","tags":["Flows"],"summary":"Get the stored retry-data snapshot for an error","description":"Returns the per-record snapshot the runtime captured at the moment of failure — the shape that\n`POST .../retry` re-feeds into the flow pipeline. The response is an envelope: `data` carries the\nadaptor-specific record payload; surrounding fields (`stage`, `pgExportId`, `oneToMany`,\n`pathToMany`, `childIndex`, `traceKey`) identify where in the pipeline the record was when it\nfailed and how it's structured.\n\nThe `data` field is the record as it reached the failing step — on an HTTP import, before the\nimport's mappings, not the request the import sent. Use `PUT .../{retryDataKey}/data` to mutate\nthe snapshot before retrying. Only errors with a `retryDataKey` expose this endpoint;\nconnection-class errors are rejected with `no_retrydata_found`. The `stage` field indicates\nwhere the retry will resume: `page_processor_import` re-runs the import (most common),\n`page_generator` means the error was upstream of the processor.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"retryDataKey","in":"path","required":true,"description":"The `retryDataKey` from the error record.","schema":{"type":"string"}}],"responses":{"200":{"description":"The stored retry-data snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRetryData"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"No snapshot exists for this key. Body: `{\"errors\":[{\"code\":\"no_retrydata_found\",\"message\":\"No\nretry data found for the given retryDataKey.\"}]}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Update the stored retry-data snapshot for an error

> \*\*Full-replace\*\* of the stored per-record snapshot. The body becomes the new payload that\
> \`POST .../retry\` will feed back into the pipeline. Same envelope shape as the matching GET — send\
> the whole object (not just \`data\`), optionally mutated.\
> \
> The typical workflow is: \`GET .../{retryDataKey}/data\`, mutate \`data\` locally, \`PUT\` the whole\
> envelope back, then \`POST .../retry\` with the same \`retryDataKey\`. Send the complete envelope\
> — omitted fields are lost, and \`retryDataKey\`, \`stage\`, \`pgExportId\` must match the original GET.\
> Editing the snapshot does not clear the error; it stays open until a subsequent retry or\
> manual resolve.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRetryData":{"type":"object","description":"Envelope around a per-record snapshot captured at the moment an error occurred. Returned by\n`GET /v1/flows/{_id}/{_stepId}/{retryDataKey}/data` and accepted (full-replace) by the PUT on the\nsame path.\n\nThe `data` field carries the record as it reached the failing step, which a retry runs through\nthat step again — its shape is adaptor-specific. The surrounding fields identify where in the\npipeline the failure happened and how the record was structured.","properties":{"retryDataKey":{"type":"string","description":"Echoes the path parameter."},"data":{"description":"The record as it reached the step. On an HTTP import it is the incoming record, before the\nimport's mappings — not the request body the import sent or the response it got back — and a\nretry maps it again with the import's current mappings, so a mapping fix reaches the retried\nrecord. Shape varies by adaptor.","additionalProperties":true},"stage":{"type":"string","description":"Pipeline stage where the record was when the error occurred."},"pgExportId":{"type":"string","format":"objectId","description":"Id of the page-generator export that originated this record."},"oneToMany":{"type":"boolean","description":"Whether the stored record represents a one-to-many expansion. When `true`, `childIndex` and\n`pathToMany` locate the specific sub-record inside the parent payload."},"pathToMany":{"type":["string","null"],"description":"JSON-path / dot-path into the parent payload naming the array of sub-records. Null on one-to-one records."},"childIndex":{"type":["integer","null"],"description":"Zero-based index into the `pathToMany` array when `oneToMany: true`. Null on one-to-one records."},"traceKey":{"type":["string","null"],"description":"Trace identifier for cross-bubble stitching in execution logs. Populated when the source export\nhas a `traceKeyTemplate` configured."},"adaptorResponse":{"type":"object","additionalProperties":true,"description":"Adaptor-level response envelope captured alongside the record payload. Present on failures\nreturned by an HTTP or import adaptor; carries fields like `data[]`, `errors[]`,\n`subGroupIdMapForSuccess`, `resultRecordIds`, `dataURIs`, `groupId`, `recordId`,\nand `ignoredResults`. Treat the shape as opaque — it varies by adaptor — and pass it through\nunchanged when PUT-ing the envelope back."}},"required":["retryDataKey","data","stage","oneToMany"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/{retryDataKey}/data":{"put":{"operationId":"updateFlowStepErrorData","tags":["Flows"],"summary":"Update the stored retry-data snapshot for an error","description":"**Full-replace** of the stored per-record snapshot. The body becomes the new payload that\n`POST .../retry` will feed back into the pipeline. Same envelope shape as the matching GET — send\nthe whole object (not just `data`), optionally mutated.\n\nThe typical workflow is: `GET .../{retryDataKey}/data`, mutate `data` locally, `PUT` the whole\nenvelope back, then `POST .../retry` with the same `retryDataKey`. Send the complete envelope\n— omitted fields are lost, and `retryDataKey`, `stage`, `pgExportId` must match the original GET.\nEditing the snapshot does not clear the error; it stays open until a subsequent retry or\nmanual resolve.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"retryDataKey","in":"path","required":true,"description":"The `retryDataKey` from the error record.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRetryData"}}}},"responses":{"204":{"description":"Snapshot updated (no body)."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"No snapshot exists for this key. Body: `{\"errors\":[{\"code\":\"no_retrydata_found\",\"message\":\"No\nretry data found for the given retryDataKey.\"}]}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get a signed URL to download file-type retry data

> Returns a pre-signed S3 URL for downloading the raw retry data file associated with an error.\
> This only works for \*\*file-type\*\* retry data (e.g. file-based exports/imports). For standard\
> record-based retry data, use \`GET .../{ retryDataKey}/data\` instead.\
> \
> File-based adaptors (FTP, S3, etc.) store retry data as files; record-based adaptors store\
> JSON snapshots accessible via \`GET .../{ retryDataKey}/data\` instead. The signed URL requires\
> no auth headers.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepSignedURLResponse":{"type":"object","description":"Pre-signed S3 URL for downloading error or retry data as a CSV file. The URL expires after\napproximately 15 minutes. Returned by the `signedURL` endpoints on errors, resolved errors,\nand retry data.","properties":{"signedURL":{"type":"string","format":"uri","description":"Pre-signed S3 URL that streams a CSV file when fetched with a plain GET (no auth headers\nneeded). Expires ~15 minutes after generation. The CSV always includes a header row, even\nwhen there are zero matching records."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/{retryDataKey}/signedURL":{"get":{"operationId":"getFlowStepRetryDataSignedURL","tags":["Flows"],"summary":"Get a signed URL to download file-type retry data","description":"Returns a pre-signed S3 URL for downloading the raw retry data file associated with an error.\nThis only works for **file-type** retry data (e.g. file-based exports/imports). For standard\nrecord-based retry data, use `GET .../{ retryDataKey}/data` instead.\n\nFile-based adaptors (FTP, S3, etc.) store retry data as files; record-based adaptors store\nJSON snapshots accessible via `GET .../{ retryDataKey}/data` instead. The signed URL requires\nno auth headers.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"retryDataKey","in":"path","required":true,"description":"The `retryDataKey` from the error record.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-signed S3 URL for the retry data file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepSignedURLResponse"}}}},"400":{"description":"The retry data for this key is not file-type. Use `GET .../{ retryDataKey}/data` for\nstandard record-based retry data. Error code: `invalid_operation`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"No retry data found for the given key. Error code: `no_retrydata_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get the HTTP request/response for an errored record

> Returns the decoded HTTP request and response the runtime captured at the moment an error occurred,\
> looked up by the opaque \`reqAndResKey\` found on each error in \`GET .../errors\`.\
> \
> Sensitive values are masked \*\*before\*\* storage — query-string credentials, \`Authorization\` headers,\
> OAuth bearer tokens, and similar are rendered as \`\*\*\*\*\*\*\*\*\`. You cannot recover the original values\
> from this endpoint.\
> \
> The \`time\` and \`response.receivedAt\` fields are epoch milliseconds, useful for correlating\
> with target-system logs. Not every error has a stored trace — record-level errors from\
> non-HTTP adaptors (e.g. NetSuite distributed imports) lack a \`reqAndResKey\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRequestResponse":{"type":"object","description":"Decoded HTTP request / response pair captured for a flow-step error. Retrieved via\n`GET /v1/flows/{_id}/{_stepId}/requests/{reqAndResKey}`. Sensitive query-string and header values\n(credentials, access tokens) are masked with `********` before storage.","properties":{"request":{"type":"object","description":"The outbound HTTP request the runtime issued.","properties":{"method":{"type":"string","description":"HTTP method (`GET`, `POST`, …)."},"url":{"type":"string","description":"Full URL sent, with sensitive query-string values masked."},"headers":{"type":"object","description":"Headers sent with the request (sensitive values masked).","additionalProperties":{"type":"string"}},"body":{"type":"string","description":"Request body, when applicable. String for JSON/XML payloads, omitted for GETs without a body."}}},"response":{"type":"object","description":"The response the runtime received.","properties":{"statusCode":{"type":"integer","description":"HTTP status code."},"headers":{"type":"object","description":"Response headers.","additionalProperties":{"type":"string"}},"body":{"type":"string","description":"Response body as received. Typically a string (JSON/XML/text); binary responses are base64-encoded."},"receivedAt":{"type":"integer","format":"int64","description":"Epoch milliseconds when the response was received."}}},"key":{"type":"string","description":"Echoes the `reqAndResKey` path parameter."},"id":{"type":"string","description":"Internal storage id for this request/response pair."},"time":{"type":"integer","format":"int64","description":"Epoch milliseconds when this pair was stored."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/requests/{reqAndResKey}":{"get":{"operationId":"getFlowStepRequestDetail","tags":["Flows"],"summary":"Get the HTTP request/response for an errored record","description":"Returns the decoded HTTP request and response the runtime captured at the moment an error occurred,\nlooked up by the opaque `reqAndResKey` found on each error in `GET .../errors`.\n\nSensitive values are masked **before** storage — query-string credentials, `Authorization` headers,\nOAuth bearer tokens, and similar are rendered as `********`. You cannot recover the original values\nfrom this endpoint.\n\nThe `time` and `response.receivedAt` fields are epoch milliseconds, useful for correlating\nwith target-system logs. Not every error has a stored trace — record-level errors from\nnon-HTTP adaptors (e.g. NetSuite distributed imports) lack a `reqAndResKey`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"reqAndResKey","in":"path","required":true,"description":"The `reqAndResKey` value from the error record.","schema":{"type":"string"}}],"responses":{"200":{"description":"Decoded request/response pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRequestResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"The key did not match any stored trace (purged, expired, or never captured). Error code:\n`file_not_found`; message: \"We are unable to find the file for the given fileName.\"\nAlso returned when the flow or step id is unknown (code: `invalid_ref`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## List stored HTTP request/response traces for a flow step

> Returns a paginated list of HTTP request/response trace metadata for a flow step, filtered by\
> time window, status code, method, and/or pipeline stage. Each entry contains summary metadata —\
> use \`GET .../requests/{reqAndResKey}\` to fetch the full decoded request/response pair for a\
> specific trace.\
> \
> \*\*Important:\*\* Time parameters (\`time\_lte\`, \`time\_gt\`) must be epoch milliseconds (integers),\
> not ISO 8601 strings.\
> \
> Use \`GET .../requests/{reqAndResKey}\` to drill into individual request/response bodies.\
> \`statusCode\` is returned as a string, not an integer. For oversized bodies stored in S3,\
> follow up with \`GET .../requests/{key}/files/signedURL\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRequestsListResponse":{"type":"object","description":"Paginated list of stored HTTP request/response trace metadata for a flow step. Returned by\n`GET /v1/flows/{_id}/{_stepId}/requests`. Follow `nextPageURL` for additional pages; each page\nadjusts the `time_lte` window by 600000 ms (10 minutes).","properties":{"requests":{"type":"array","description":"Trace metadata entries for the current page.","items":{"type":"object","properties":{"key":{"type":"string","description":"Opaque key identifying this request/response pair (the `reqAndResKey`)."},"time":{"type":"integer","format":"int64","description":"Epoch milliseconds when the request was captured."},"method":{"type":"string","description":"HTTP method used (`GET`, `POST`, `PUT`, etc.)."},"statusCode":{"type":"string","description":"HTTP status code as a string (e.g. `\"200\"`, `\"403\"`)."},"stage":{"type":"string","description":"Pipeline stage where the request was captured (e.g. `export`, `import`)."}}}},"nextPageURL":{"type":["string","null"],"description":"Full URL for the next page of results, or `null` when there are no more pages. Each page\nshifts `time_lte` backward by 600000 ms (10 minutes)."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/requests":{"get":{"operationId":"listFlowStepRequests","tags":["Flows"],"summary":"List stored HTTP request/response traces for a flow step","description":"Returns a paginated list of HTTP request/response trace metadata for a flow step, filtered by\ntime window, status code, method, and/or pipeline stage. Each entry contains summary metadata —\nuse `GET .../requests/{reqAndResKey}` to fetch the full decoded request/response pair for a\nspecific trace.\n\n**Important:** Time parameters (`time_lte`, `time_gt`) must be epoch milliseconds (integers),\nnot ISO 8601 strings.\n\nUse `GET .../requests/{reqAndResKey}` to drill into individual request/response bodies.\n`statusCode` is returned as a string, not an integer. For oversized bodies stored in S3,\nfollow up with `GET .../requests/{key}/files/signedURL`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"time_lte","in":"query","required":false,"description":"Upper bound of the time window (inclusive), as epoch milliseconds. Defaults to now if\nomitted.","schema":{"type":"integer","format":"int64"}},{"name":"time_gt","in":"query","required":false,"description":"Lower bound of the time window (exclusive), as epoch milliseconds.","schema":{"type":"integer","format":"int64"}},{"name":"statusCode","in":"query","required":false,"description":"Filter to traces with this HTTP status code (e.g. `403`, `500`).","schema":{"type":"string"}},{"name":"method","in":"query","required":false,"description":"Filter to traces with this HTTP method (e.g. `GET`, `POST`).","schema":{"type":"string"}},{"name":"stage","in":"query","required":false,"description":"Filter to traces captured at this pipeline stage (e.g. `export`, `import`).","schema":{"type":"string"}}],"responses":{"200":{"description":"One page of request/response trace metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRequestsListResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"Time parameters were passed as ISO strings instead of epoch milliseconds. Error code:\n`invalid_or_missing_field`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Delete stored HTTP request/response traces by key

> Permanently removes specific stored request+response pairs from the per-step trace cache. Despite\
> the un-parameterized path, this is \*\*not\*\* a blanket purge — the request body must name the exact\
> \`reqAndResKey\` values to delete (from the errors listing). After deletion, subsequent calls to\
> \`GET .../requests/{reqAndResKey}\` for the deleted keys fail with \`file\_not\_found\`.\
> \
> The live API \*\*requires \`Content-Type: application/json\`\*\* plus a non-empty \`keys\[]\` array. A\
> request with no body, \`{}\`, or \`{keys: \[]}\` rejects with 400 \`invalid\_url\` / \`"keys is not valid."\`.\
> \
> The underlying error record in \`GET .../errors\` remains after deletion, but its \`reqAndResKey\`\
> pointer will dangle. There is no single "purge all" call — enumerate current errors and collect\
> all \`reqAndResKey\` values to clear the full cache.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepRequestsDeleteRequest":{"type":"object","description":"Request body for `DELETE /v1/flows/{_id}/{_stepId}/requests`. Targets specific stored\nrequest/response traces for deletion by their opaque `reqAndResKey` identifiers — this is **not** a\nblanket-purge endpoint despite the un-parameterized path.","properties":{"keys":{"type":"array","description":"`reqAndResKey` values to delete, as listed on each error from `GET /v1/flows/{_id}/{_stepId}/errors`.\nEmpty array rejects with 400 (`invalid_url` / \"keys is not valid\"); to purge everything, enumerate\nthe current errors' keys and send them.","minItems":1,"items":{"type":"string"}}},"required":["keys"]},"FlowStepRequestsDeleteResponse":{"type":"object","description":"Result of `DELETE /v1/flows/{_id}/{_stepId}/requests`. Lists which requested keys were deleted and\nany per-key errors the platform encountered.","properties":{"deleted":{"type":"array","description":"Keys that were successfully deleted. Subset of the request's `keys[]`.","items":{"type":"string"}},"errors":{"type":"array","description":"Per-key error objects for entries that failed to delete (already gone, permission, etc.). Empty\narray on fully-successful calls.","items":{"type":"object","additionalProperties":true}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/requests":{"delete":{"operationId":"deleteFlowStepRequests","tags":["Flows"],"summary":"Delete stored HTTP request/response traces by key","description":"Permanently removes specific stored request+response pairs from the per-step trace cache. Despite\nthe un-parameterized path, this is **not** a blanket purge — the request body must name the exact\n`reqAndResKey` values to delete (from the errors listing). After deletion, subsequent calls to\n`GET .../requests/{reqAndResKey}` for the deleted keys fail with `file_not_found`.\n\nThe live API **requires `Content-Type: application/json`** plus a non-empty `keys[]` array. A\nrequest with no body, `{}`, or `{keys: []}` rejects with 400 `invalid_url` / `\"keys is not valid.\"`.\n\nThe underlying error record in `GET .../errors` remains after deletion, but its `reqAndResKey`\npointer will dangle. There is no single \"purge all\" call — enumerate current errors and collect\nall `reqAndResKey` values to clear the full cache.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRequestsDeleteRequest"}}}},"responses":{"200":{"description":"Per-key deletion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepRequestsDeleteResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"415":{"description":"`Content-Type: application/json` header is missing."}}}}}}
```

## Get a signed URL for an oversized request/response body

> Returns a pre-signed S3 URL for downloading the full request or response body when it was too\
> large to store inline in the trace record. Most request/response pairs have inline bodies\
> accessible via \`GET .../requests/{reqAndResKey}\` — this endpoint is only needed for the subset\
> where the body was offloaded to S3 due to size.\
> \
> Call \`GET .../requests/{reqAndResKey}\` first. If \`request.body\` or \`response.body\` is\
> truncated or missing, use this endpoint to fetch the full payload from S3.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepSignedURLResponse":{"type":"object","description":"Pre-signed S3 URL for downloading error or retry data as a CSV file. The URL expires after\napproximately 15 minutes. Returned by the `signedURL` endpoints on errors, resolved errors,\nand retry data.","properties":{"signedURL":{"type":"string","format":"uri","description":"Pre-signed S3 URL that streams a CSV file when fetched with a plain GET (no auth headers\nneeded). Expires ~15 minutes after generation. The CSV always includes a header row, even\nwhen there are zero matching records."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/requests/{key}/files/signedURL":{"get":{"operationId":"getFlowStepRequestFilesSignedURL","tags":["Flows"],"summary":"Get a signed URL for an oversized request/response body","description":"Returns a pre-signed S3 URL for downloading the full request or response body when it was too\nlarge to store inline in the trace record. Most request/response pairs have inline bodies\naccessible via `GET .../requests/{reqAndResKey}` — this endpoint is only needed for the subset\nwhere the body was offloaded to S3 due to size.\n\nCall `GET .../requests/{reqAndResKey}` first. If `request.body` or `response.body` is\ntruncated or missing, use this endpoint to fetch the full payload from S3.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}},{"name":"key","in":"path","required":true,"description":"The `reqAndResKey` value from the request trace.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-signed S3 URL for the oversized body file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepSignedURLResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"The S3 file does not exist — it was purged or was never offloaded. Error code:\n`file_not_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request/response pair has an inline body — there is no offloaded file to download.\nError code: `missing_bodykey`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Set tags on a batch of errors

> \*\*Full-replace\*\* per-error: for each \`(errorId, retryDataKey)\` in the body, the stored tag set is\
> replaced with \`tagIds\`. Pass \`tagIds: \[]\` to clear all tags from the listed errors.\
> \
> Tags are account-scoped short codes (from \`GET /v1/tags\`) — not free-form strings. The \`tagId\` you\
> send here is the short code (e.g. \`F3ZBQ\`), \*\*not\*\* the tag document's Mongo \`\_id\`.\
> \
> The errors batch uses short keys (\`id\` = errorId, \`rdk\` = retryDataKey) to minimize body size.\
> Use \`rdk: ""\` for errors without a \`retryDataKey\` (connection-class errors). This endpoint\
> replaces the full tag set per error — to add a tag without removing existing ones, merge\
> client-side first.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowStepTagsRequest":{"type":"object","description":"Request body for `PUT /v1/flows/{_id}/{_stepId}/tags`. Replaces the tag set on each listed error\nwith `tagIds`. Pass an empty `tagIds` array to clear all tags from the listed errors.","properties":{"errors":{"type":"array","description":"Error identifiers to retag. Each entry pairs an `errorId` with its opaque `retryDataKey` (when\npresent). Both fields from the `GET .../errors` response.","minItems":1,"items":{"type":"object","properties":{"id":{"type":"string","description":"Error id (`errorId` from the listing)."},"rdk":{"type":"string","description":"Retry data key (`retryDataKey` from the listing). Required when the error has one: an\nentry without it fails with 404 `invalid_errorid`. Send an empty string, or omit it,\nonly when the error has none."}},"required":["id"]}},"tagIds":{"type":"array","description":"Short tag codes to apply. Obtain from `GET /v1/tags` — use the short `tagId` field (e.g.\n`F3ZBQ`), not the Mongo `_id`. Pass `[]` to remove all tags from the listed errors.\nAt most 3 tag codes per error (platform-enforced).","maxItems":3,"items":{"type":"string"}}},"required":["errors","tagIds"]},"FlowStepTagsResponse":{"type":"object","description":"Echo of which error records the tag mutation touched, split by their current state. Returned by\n`PUT /v1/flows/{_id}/{_stepId}/tags`.","properties":{"errorsToReturn":{"type":"object","description":"Ids split by whether each error was open or already resolved when retagged.","properties":{"errors":{"type":"array","description":"Ids of **open** errors that were retagged.","items":{"type":"string"}},"resolved":{"type":"array","description":"Ids of **resolved** errors that were retagged.","items":{"type":"string"}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/{_stepId}/tags":{"put":{"operationId":"updateFlowStepErrorTags","tags":["Flows"],"summary":"Set tags on a batch of errors","description":"**Full-replace** per-error: for each `(errorId, retryDataKey)` in the body, the stored tag set is\nreplaced with `tagIds`. Pass `tagIds: []` to clear all tags from the listed errors.\n\nTags are account-scoped short codes (from `GET /v1/tags`) — not free-form strings. The `tagId` you\nsend here is the short code (e.g. `F3ZBQ`), **not** the tag document's Mongo `_id`.\n\nThe errors batch uses short keys (`id` = errorId, `rdk` = retryDataKey) to minimize body size.\nUse `rdk: \"\"` for errors without a `retryDataKey` (connection-class errors). This endpoint\nreplaces the full tag set per error — to add a tag without removing existing ones, merge\nclient-side first.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepTagsRequest"}}}},"responses":{"200":{"description":"Tags updated. Body echoes affected ids split by current state (open vs resolved).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStepTagsResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Delete execution logs for a flow within a time range

> Asynchronously deletes execution-log entries for the flow that fall within the specified time range.\
> Returns \`202 Accepted\` with an empty body — the deletion runs in the background.\
> \
> Both \`startedAt\` and \`endAt\` are required query parameters and must be valid ISO 8601 datetime strings.\
> \`startedAt\` must be strictly before \`endAt\`; the server returns \`400 invalid\_query\_params\` otherwise.\
> \
> This is a destructive, irreversible operation. The 202 response does not include a job id;\
> there is no way to poll for completion.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/logs":{"delete":{"operationId":"deleteFlowLogs","tags":["Flows"],"summary":"Delete execution logs for a flow within a time range","description":"Asynchronously deletes execution-log entries for the flow that fall within the specified time range.\nReturns `202 Accepted` with an empty body — the deletion runs in the background.\n\nBoth `startedAt` and `endAt` are required query parameters and must be valid ISO 8601 datetime strings.\n`startedAt` must be strictly before `endAt`; the server returns `400 invalid_query_params` otherwise.\n\nThis is a destructive, irreversible operation. The 202 response does not include a job id;\nthere is no way to poll for completion.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"startedAt","in":"query","required":true,"description":"Start of the time range (inclusive). ISO 8601 datetime. Must be before `endAt`.","schema":{"type":"string","format":"date-time"}},{"name":"endAt","in":"query","required":true,"description":"End of the time range (inclusive). ISO 8601 datetime. Must be after `startedAt`.","schema":{"type":"string","format":"date-time"}}],"responses":{"202":{"description":"Accepted — log deletion is running asynchronously."},"400":{"description":"Missing or invalid query parameters. Returned when `startedAt` or `endAt` is absent, not a valid\nISO datetime, or when `startedAt` is not before `endAt`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Cancel all running jobs for a flow

> Cancels every currently running job for the specified flow. This is the flow-scoped equivalent\
> of cancelling individual jobs via \`PUT /v1/jobs/{\_id}\` — it finds all in-progress jobs for the\
> flow and requests cancellation in a single call.\
> \
> No request body is required. The response is an empty 204 on success.\
> \
> Cancellation is asynchronous — jobs may take a few seconds to fully stop after the 204 is\
> returned.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flows/{_id}/jobs/cancel":{"post":{"operationId":"cancelFlowJobs","tags":["Flows"],"summary":"Cancel all running jobs for a flow","description":"Cancels every currently running job for the specified flow. This is the flow-scoped equivalent\nof cancelling individual jobs via `PUT /v1/jobs/{_id}` — it finds all in-progress jobs for the\nflow and requests cancellation in a single call.\n\nNo request body is required. The response is an empty 204 on success.\n\nCancellation is asynchronous — jobs may take a few seconds to fully stop after the 204 is\nreturned.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Cancellation requested for all running jobs. No response body."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Search jobs within a flow by trace key

> Searches for flow-run jobs that contain records matching a trace key prefix. Returns up to 1000\
> matching job objects — there is no pagination beyond that limit. A run matches when it carried\
> a matching record at all, whether the record succeeded, failed or was ignored there (live probe,\
> 2026-10-21). Very short prefixes can match nothing — in that probe a two-character prefix of a\
> nine-character key found no run while three characters did — so send the record's whole trace\
> key.\
> \
> The \`traceKeyPrefix\` query parameter is required; the server returns \`400\` ("traceKeyPrefix is\
> required.") when it is missing.\
> \
> \`status\` filters the runs: in the same probe \`status=failed\` left out a \`completed\` run that\
> \`status=completed\` returned, and a value that is not a job status was ignored.\
> \
> Narrow the window with \`createdAt\_gte\` / \`createdAt\_lte\` when there are many runs for the\
> flow.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowJobsSearchResponse":{"type":"object","description":"Response for a flow-job search by trace key. Returns up to 1000 matching job objects.\nThere is no pagination — the result set is capped at 1000.","properties":{"runs":{"type":"array","description":"Matching job objects.","items":{"type":"object","description":"A flow-run job summary.","properties":{"_id":{"type":"string","format":"objectId","description":"Job id."},"_flowId":{"type":"string","format":"objectId","description":"Flow id that owns this job."},"type":{"type":"string","description":"Job type — always `flow` for flow-run jobs."},"status":{"type":"string","description":"Terminal status of the job."},"startedAt":{"type":"string","format":"date-time","description":"When the job started."},"endedAt":{"type":"string","format":"date-time","description":"When the job finished."},"numSuccess":{"type":"integer","description":"Count of records that completed successfully."},"numError":{"type":"integer","description":"Count of records that errored."},"numIgnore":{"type":"integer","description":"Count of records that were ignored (filtered out)."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/jobs/search":{"get":{"operationId":"searchFlowJobs","tags":["Flows"],"summary":"Search jobs within a flow by trace key","description":"Searches for flow-run jobs that contain records matching a trace key prefix. Returns up to 1000\nmatching job objects — there is no pagination beyond that limit. A run matches when it carried\na matching record at all, whether the record succeeded, failed or was ignored there (live probe,\n2026-10-21). Very short prefixes can match nothing — in that probe a two-character prefix of a\nnine-character key found no run while three characters did — so send the record's whole trace\nkey.\n\nThe `traceKeyPrefix` query parameter is required; the server returns `400` (\"traceKeyPrefix is\nrequired.\") when it is missing.\n\n`status` filters the runs: in the same probe `status=failed` left out a `completed` run that\n`status=completed` returned, and a value that is not a job status was ignored.\n\nNarrow the window with `createdAt_gte` / `createdAt_lte` when there are many runs for the\nflow.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"traceKeyPrefix","in":"query","required":true,"description":"Trace key prefix to search for. The server matches job records whose `traceKey` begins with\nthis value, but very short prefixes can match nothing: in a live probe (2026-10-21) a\ntwo-character prefix of a nine-character key found no run while three characters did. Send\nthe record's whole trace key.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Job status filter: only runs with this status are returned. A value that is not a job\nstatus is ignored (live probe, 2026-10-21).","schema":{"type":"string"}},{"name":"createdAt_gte","in":"query","required":false,"description":"Only return jobs created at or after this ISO 8601 datetime.","schema":{"type":"string","format":"date-time"}},{"name":"createdAt_lte","in":"query","required":false,"description":"Only return jobs created at or before this ISO 8601 datetime.","schema":{"type":"string","format":"date-time"}},{"name":"pageSize","in":"query","required":false,"description":"Maximum number of jobs to return. Capped at 1000.","schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"Matching job objects (max 1000).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowJobsSearchResponse"}}}},"400":{"description":"Missing required `traceKeyPrefix` query parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## List execution log entries for a flow run

> Returns one page of execution-log entries for a specific flow run — one entry per record-at-step\
> (export or import). Entries carry the \`(\_expOrImpId, groupId, recordId, traceKey)\` tuple needed to\
> drill into per-stage metadata and data via the \`logs/metadata/query\` and \`logs/data/query\` endpoints.\
> \
> Execution logs are captured only for a run with a logging level — the job's \`logMode\` — set by the\
> flow's \`logging.mode\` or an open \`logging.debugUntil\` window. While the account-level logging\
> preference is off, a flow set to \`basic\` captures nothing and its jobs carry no \`logMode\`. Jobs older\
> than the flow's log retention window will return an empty \`logs\` array.\
> \
> For per-stage data (an HTTP request and response, or a mapping's or script hook's input and\
> output), pick an entry and call \`POST .../logs/data/query\` with the corresponding \`stage\`. To stitch an\
> export entry to its downstream imports, use the \`traceKey\` with\
> \`POST .../logs/metadata/query\`.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ExecutionLogsResponse":{"type":"object","description":"One page of execution-log entries for a flow run. Pagination is body-driven: follow `nextPageUrl`\nto fetch the next page (null when the page is the last). `prevPageUrl` is populated for navigation\nbackward from a mid-history page.","properties":{"logs":{"type":"array","description":"Log entries in this page. Ordered newest-first.","items":{"$ref":"#/components/schemas/ExecutionLogEntry"}},"nextPageUrl":{"type":["string","null"],"description":"URL (absolute or path-relative) for the next page, or `null` on the last page."},"prevPageUrl":{"type":["string","null"],"description":"URL for the previous page, or `null` when already at the head."}}},"ExecutionLogEntry":{"type":"object","description":"One entry in a flow-run's execution log. Each entry represents a single record processed by a single step\n(export or import) and carries the identifiers needed to drill into per-stage traces via\n`POST /v1/flows/{_id}/jobs/{_jobId}/logs/metadata/query` and `.../logs/data/query`.\n\nThe tuple `(_expOrImpId, groupId, recordId)` uniquely identifies the record-at-step; `traceKey` groups\nthe paired export and import entries that processed the same record end-to-end.","properties":{"startedAt":{"type":"string","format":"date-time","description":"When this step began processing the record."},"recordId":{"type":"string","description":"Opaque per-record identifier. Feed this (together with `groupId` and `_expOrImpId`) into the metadata/data query endpoints."},"groupId":{"type":"string","description":"Opaque batch identifier — records processed in the same page/batch share a groupId."},"traceKey":{"type":"string","description":"Trace identifier that pairs an export entry with the import entries that processed its output.\nPass as `traceKey` to `metadata/query` to get a traceView across paired steps."},"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step that produced this entry."},"status":{"type":"string","description":"Outcome of this step for this record.","enum":["success","error","ignore"]},"timeTaken":{"type":"integer","description":"Milliseconds spent processing this record at this step."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/jobs/{_jobId}/logs":{"get":{"operationId":"listFlowExecutionLogs","tags":["Flows"],"summary":"List execution log entries for a flow run","description":"Returns one page of execution-log entries for a specific flow run — one entry per record-at-step\n(export or import). Entries carry the `(_expOrImpId, groupId, recordId, traceKey)` tuple needed to\ndrill into per-stage metadata and data via the `logs/metadata/query` and `logs/data/query` endpoints.\n\nExecution logs are captured only for a run with a logging level — the job's `logMode` — set by the\nflow's `logging.mode` or an open `logging.debugUntil` window. While the account-level logging\npreference is off, a flow set to `basic` captures nothing and its jobs carry no `logMode`. Jobs older\nthan the flow's log retention window will return an empty `logs` array.\n\nFor per-stage data (an HTTP request and response, or a mapping's or script hook's input and\noutput), pick an entry and call `POST .../logs/data/query` with the corresponding `stage`. To stitch an\nexport entry to its downstream imports, use the `traceKey` with\n`POST .../logs/metadata/query`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_jobId","in":"path","required":true,"description":"Flow-run job id (the `_id` of a `type: \"flow\"` job).","schema":{"type":"string","format":"objectId"}},{"name":"status","in":"query","required":false,"description":"Filter log entries by record outcome.","schema":{"type":"string","enum":["success","error","ignore"]}},{"name":"_expOrImpId","in":"query","required":false,"description":"Comma-separated list of export or import step ids. Only entries produced by these steps are returned.","schema":{"type":"string"}},{"name":"traceKeyPrefix","in":"query","required":false,"description":"Filter entries whose `traceKey` starts with this prefix.","schema":{"type":"string"}},{"name":"sortOrder","in":"query","required":false,"description":"Sort direction for log entries by `startedAt`. Defaults to descending (newest first).","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"pageSize","in":"query","required":false,"description":"Number of log entries per page. Must be between 1 and 1000.","schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"One page of execution-log entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionLogsResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Query execution-log metadata for a record-at-step

> Returns per-step timing and outcome metadata for a single record as it traveled through a flow run.\
> When the request includes \`traceKey\`, the response spans every step that shared that trace — typically\
> the source export plus its downstream imports.\
> \
> Pull the \`\_expOrImpId\`, \`groupId\`, \`recordId\`, and (optionally) \`traceKey\` values from a\
> \`GET /v1/flows/{\_id}/jobs/{\_jobId}/logs\` entry.\
> \
> Pair this with \`logs/data/query\` to build a full per-record trace: this endpoint shows which\
> steps were touched and timing; the data endpoint returns actual payloads. When\
> \`duplicateTraceKey\` is \`true\`, the traceKey was seen on more than one record in the job, so\
> results may mix records from retries or fan-out. Without \`traceKey\` in the request,\
> \`traceView\` is \`false\` and only the single queried step is returned.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ExecutionLogMetadataRequest":{"type":"object","description":"Request body for `POST /v1/flows/{_id}/jobs/{_jobId}/logs/metadata/query`.\nIdentifies a single record-at-step within the job's execution log. Include `traceKey` to widen\nthe result to every step that shared that trace (export paired with its downstream imports).","properties":{"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step the record was processed by."},"groupId":{"type":"string","description":"The `groupId` from the matching `execution-log` entry."},"recordId":{"type":"string","description":"The `recordId` from the matching `execution-log` entry."},"traceKey":{"type":"string","description":"Optional. When provided, the response includes a `traceView` across every step that shared this trace key\n(e.g. the original export plus its downstream imports)."}},"required":["_expOrImpId","groupId","recordId"]},"ExecutionLogMetadataResponse":{"type":"object","description":"Metadata for a single record-at-step (or for every step sharing a `traceKey` when the request supplied one).\nReturned by `POST /v1/flows/{_id}/jobs/{_jobId}/logs/metadata/query`.","properties":{"traceKey":{"type":"string","description":"Echoed back when the request supplied a `traceKey`; omitted otherwise."},"duplicateTraceKey":{"type":"boolean","description":"`true` when the same traceKey was seen on more than one record in this job — useful for spotting\nrecords that got retried or fanned out and may need disambiguation when rendering the trace view."},"traceView":{"type":"boolean","description":"`true` when the response contains a multi-step trace (i.e. the request supplied `traceKey` and paired\nsteps were found). `false` when the response is scoped to the single queried step."},"steps":{"type":"array","description":"Per-step metadata. A single entry when `traceView` is false; one per paired step otherwise.","items":{"$ref":"#/components/schemas/ExecutionLogStep"}}}},"ExecutionLogStep":{"type":"object","description":"Per-step timing and outcome for a single record as it passed through one export or import.","properties":{"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step."},"recordId":{"type":"string","description":"Opaque per-record id; pair with `groupId` + `_expOrImpId` when fetching stage data."},"groupId":{"type":"string","description":"Opaque batch id."},"status":{"type":"string","description":"Outcome at this step.","enum":["success","error","ignore"]},"timeTaken":{"type":"integer","description":"Milliseconds spent at this step for this record."},"startedAt":{"type":"string","description":"Step start time. Format is `YYYY-MM-DD HH:MM:SS.sss` (no `T`, no `Z`)."},"completedAt":{"type":"string","description":"Step completion time. Same format as `startedAt`."},"stage":{"type":"string","description":"Pipeline stage at which this step entry was recorded. Observed values include `apiCall`\n(the adaptor invocation itself). Useful for filtering metadata responses when a step has\nmultiple stage entries across a single record's pass.\n\nOn an entry with `status: ignore`, the stage that skipped the record, recorded even on a run\nlogged at `basic` (whose stage data is empty): `inputFilter` for the step's filter,\n`preMapHook` for a preMap hook that returned no data for the record, and an empty string for\nan ignore-existing rule."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/jobs/{_jobId}/logs/metadata/query":{"post":{"operationId":"queryFlowExecutionLogMetadata","tags":["Flows"],"summary":"Query execution-log metadata for a record-at-step","description":"Returns per-step timing and outcome metadata for a single record as it traveled through a flow run.\nWhen the request includes `traceKey`, the response spans every step that shared that trace — typically\nthe source export plus its downstream imports.\n\nPull the `_expOrImpId`, `groupId`, `recordId`, and (optionally) `traceKey` values from a\n`GET /v1/flows/{_id}/jobs/{_jobId}/logs` entry.\n\nPair this with `logs/data/query` to build a full per-record trace: this endpoint shows which\nsteps were touched and timing; the data endpoint returns actual payloads. When\n`duplicateTraceKey` is `true`, the traceKey was seen on more than one record in the job, so\nresults may mix records from retries or fan-out. Without `traceKey` in the request,\n`traceView` is `false` and only the single queried step is returned.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_jobId","in":"path","required":true,"description":"Flow-run job id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionLogMetadataRequest"}}}},"responses":{"200":{"description":"Step metadata (or a trace across paired steps when `traceKey` was supplied).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionLogMetadataResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get per-stage execution log data for a record

> Returns the decoded log data for a single \`(step, stage)\` tuple within a flow run, such as the\
> HTTP request and response a step sent or the input and output of its mapping or a script hook.\
> \
> This is typically the terminal call in the drill-down sequence: \`execution-logs\` then\
> \`metadata/query\` then \`data/query\`. An empty \`logs\` array does not show that the stage ran or\
> that its name is valid: the server answers an unknown stage name the same way as a stage that\
> captured nothing, so check the stage name and the job's \`logMode\` (\`GET /v1/jobs/{\_id}\`)\
> before concluding the step recorded nothing.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ExecutionLogDataRequest":{"type":"object","description":"Request body for `POST /v1/flows/{_id}/jobs/{_jobId}/logs/data/query`.\nFetches the data one step captured at one execution stage for a record, or for the record's\nwhole group at a group-level stage.","properties":{"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step the record was processed by."},"stage":{"type":"string","description":"Execution stage whose data to return. `apiCall` holds the request and response an HTTP\nexport or import sent. On a job whose `logMode` is `debug`, an export's transform and\noutput filter record under `transformation` and `outputFilter`, an import's filter (its\n`filter` field) under `inputFilter`, an import's mapping and response mapping under\n`mapping` and `responseMapping`, and a script hook's `options` and\nreturn value under its hook type plus `Hook` (`preSavePageHook`, `preMapHook`,\n`postMapHook`, `postSubmitHook`, `postResponseMapHook`), whatever the function is called;\nneither the bare hook name (`preMap`) nor `<functionName>Hook` returns them (live-verified\n2026-10-20; `inputFilter` 2026-10-22)."},"groupId":{"type":"string","description":"Batch id from the `execution-log` entry."},"recordId":{"type":"string","description":"Record id from the `execution-log` entry."}},"required":["_expOrImpId","stage","groupId","recordId"]},"ExecutionLogDataResponse":{"type":"object","description":"Stage data one step of a flow run recorded for a record, or for the record's whole group at a\ngroup-level stage. Returned by `POST /v1/flows/{_id}/jobs/{_jobId}/logs/data/query`.\n\nThe payload inside `logs[].log` is stage-specific (live-verified 2026-10-20):\n\n- `apiCall`: the request's method and URI and the response's status code. A job whose `logMode` is\n  `detailed` or `debug` also records each side's headers and body; a `basic` job does not.\n- `mapping`, `transformation`, `outputFilter`, `inputFilter`, `responseMapping`: a per-record entry\n  carrying the record's `recordId`, the stage's `input`, and its `output`. The filter stages\n  (`outputFilter` for an export's output filter, `inputFilter` for an import's filter) have\n  `success` instead, `false` for a record the filter dropped (`inputFilter` live-verified\n  2026-10-22).\n- `preSavePageHook`, `preMapHook`, `postMapHook`, `postSubmitHook`: one entry for the record's whole\n  group, with no `recordId`. `input` is a one-element array holding the `options` the hook received,\n  and `output` holds what the hook returned.\n- `postResponseMapHook`: `recordId` is null, and `input` is the `options` object itself.","properties":{"logs":{"type":"array","description":"Array of stage-data entries. Usually length 1 when data is available, 0 otherwise.","items":{"type":"object","properties":{"log":{"type":"object","description":"The stage payload. Fields vary by the requested stage.","additionalProperties":true}}}},"errors":{"type":"array","description":"Query-scoped errors. Some adaptors (e.g. NetSuiteDistributedImport) attach the actual failure here rather\nthan inside `logs[].log.errors`. Empty on success.","items":{"type":"object","additionalProperties":true}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/jobs/{_jobId}/logs/data/query":{"post":{"operationId":"queryFlowExecutionLogData","tags":["Flows"],"summary":"Get per-stage execution log data for a record","description":"Returns the decoded log data for a single `(step, stage)` tuple within a flow run, such as the\nHTTP request and response a step sent or the input and output of its mapping or a script hook.\n\nThis is typically the terminal call in the drill-down sequence: `execution-logs` then\n`metadata/query` then `data/query`. An empty `logs` array does not show that the stage ran or\nthat its name is valid: the server answers an unknown stage name the same way as a stage that\ncaptured nothing, so check the stage name and the job's `logMode` (`GET /v1/jobs/{_id}`)\nbefore concluding the step recorded nothing.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_jobId","in":"path","required":true,"description":"Flow-run job id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionLogDataRequest"}}}},"responses":{"200":{"description":"Log entries for the requested `(step, stage)`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionLogDataResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## List child log records for a parent record

> Returns one page of child log records for a specific parent record within a flow-run step.\
> Child records represent sub-operations (e.g. individual batch items, lookup expansions, or\
> retry attempts) spawned by the parent record during step processing.\
> \
> Use the \`status\` query parameter to isolate failures within a batch.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"FlowJobLogChildrenResponse":{"type":"object","description":"Paginated response for child log records of a parent record. Follow `nextPageUrl` to fetch\nsubsequent pages; `prevPageUrl` navigates backward. Both are `null` when at the boundary.","properties":{"children":{"type":"array","description":"Child log entries in this page.","items":{"$ref":"#/components/schemas/FlowJobLogEntry"}},"nextPageUrl":{"type":["string","null"],"description":"Full URL for the next page, or `null` on the last page."},"prevPageUrl":{"type":["string","null"],"description":"Full URL for the previous page, or `null` when already at the head."}}},"FlowJobLogEntry":{"type":"object","description":"One entry in a paginated flow-job log listing. Each entry represents a single record processed by a\nsingle step (export or import) within a flow run.","properties":{"startedAt":{"type":"string","format":"date-time","description":"When this step began processing the record."},"recordId":{"type":"string","description":"Opaque per-record identifier."},"groupId":{"type":"string","description":"Opaque batch identifier — records processed in the same page/batch share a groupId."},"traceKey":{"type":"string","description":"Trace identifier that pairs an export entry with the import entries that processed its output."},"_expOrImpId":{"type":"string","format":"objectId","description":"Id of the export or import step that produced this entry."},"status":{"type":"string","description":"Outcome of this step for this record.","enum":["success","error","ignore"]},"timeTaken":{"type":"integer","description":"Milliseconds spent processing this record at this step."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/flows/{_id}/jobs/{_jobId}/{_stepId}/logs/{recordId}/children":{"get":{"operationId":"listFlowJobStepLogChildren","tags":["Flows"],"summary":"List child log records for a parent record","description":"Returns one page of child log records for a specific parent record within a flow-run step.\nChild records represent sub-operations (e.g. individual batch items, lookup expansions, or\nretry attempts) spawned by the parent record during step processing.\n\nUse the `status` query parameter to isolate failures within a batch.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"_jobId","in":"path","required":true,"description":"Flow-run job id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import step id within the flow.","schema":{"type":"string","format":"objectId"}},{"name":"recordId","in":"path","required":true,"description":"Parent record id whose children to retrieve.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Filter child records by outcome.","schema":{"type":"string","enum":["success","error","ignore"]}},{"name":"pageSize","in":"query","required":false,"description":"Number of child records per page. Must be between 1 and 1000.","schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"One page of child log records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowJobLogChildrenResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Test-run a flow

> Executes the flow in \*\*test mode\*\* and returns the test-run metadata\
> synchronously. Unlike \`POST /v1/flows/{\_id}/run\` (which queues an\
> asynchronous production job), a test run executes inline against the\
> flow's current configuration and records the per-step stages it produced.\
> \
> Test runs are kept in a \*\*separate history\*\* from production runs — the\
> \`flowJob\` and \`childJobs\` returned here are test artifacts, not records\
> you'll find via \`GET /v1/jobs\`. The top-level \`metadata\` map is keyed by\
> step id; each value is the ordered list of stage names that step produced\
> (e.g. \`request\`, \`parse\`, \`router\`, \`input\`). Use those step ids with\
> \`GET /v1/flows/{\_id}/test/run/{runId}/{\_stepId}\` to inspect per-stage\
> input/output and errors, or with\
> \`GET /v1/flows/{\_id}/test/run/{runId}/{\_stepId}/logs/requestAndResponse\`\
> for raw outbound HTTP captures.\
> \
> \*\*Endpoint template applies across three resource families.\*\* The same\
> test-run shape also exists for Tools (\`/v1/tools/{\_id}/test/run\`) and\
> builder-mode APIs (\`/v1/apis/{\_id}/test/run\`).\
> \
> A test run processes only the first page of records: later pages arrive empty, so downstream\
> steps see only the first page's records.\
> \
> Test-run state is short-lived and ephemeral — capture the \`runId\` (the\
> \`flowJob.\_id\`) and read back any step detail soon after the run returns.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flows/{_id}/test/run":{"post":{"operationId":"testRunFlow","tags":["Flows"],"summary":"Test-run a flow","description":"Executes the flow in **test mode** and returns the test-run metadata\nsynchronously. Unlike `POST /v1/flows/{_id}/run` (which queues an\nasynchronous production job), a test run executes inline against the\nflow's current configuration and records the per-step stages it produced.\n\nTest runs are kept in a **separate history** from production runs — the\n`flowJob` and `childJobs` returned here are test artifacts, not records\nyou'll find via `GET /v1/jobs`. The top-level `metadata` map is keyed by\nstep id; each value is the ordered list of stage names that step produced\n(e.g. `request`, `parse`, `router`, `input`). Use those step ids with\n`GET /v1/flows/{_id}/test/run/{runId}/{_stepId}` to inspect per-stage\ninput/output and errors, or with\n`GET /v1/flows/{_id}/test/run/{runId}/{_stepId}/logs/requestAndResponse`\nfor raw outbound HTTP captures.\n\n**Endpoint template applies across three resource families.** The same\ntest-run shape also exists for Tools (`/v1/tools/{_id}/test/run`) and\nbuilder-mode APIs (`/v1/apis/{_id}/test/run`).\n\nA test run processes only the first page of records: later pages arrive empty, so downstream\nsteps see only the first page's records.\n\nTest-run state is short-lived and ephemeral — capture the `runId` (the\n`flowJob._id`) and read back any step detail soon after the run returns.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Test run executed. Returns the per-step stage `metadata`, the test\n`flowJob`, and any `childJobs` produced by the run.","content":{"application/json":{"schema":{"type":"object","description":"Test-run result envelope.","properties":{"metadata":{"type":"object","description":"Map of step id to the ordered list of stage names that step\nproduced during the run. Step ids ending in `_input` and the\nsynthetic `main` router key are also present.","additionalProperties":{"type":"array","items":{"type":"string"}}},"flowJob":{"type":"object","description":"The test flow Job record. Its `_id` is the `runId` used to\nread per-step detail. Distinct from production Job records.","additionalProperties":true},"childJobs":{"type":"array","description":"Per-step child Job records produced during the test run.","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"Flow not found (\"The flow <_id> does not belong to the user <userId>.\"). The\nsame answer comes back for a flow that exists and has page generators but no page\nprocessor or router yet, even when `_exportId` names one of its page generators: give it\na step after the export before test-running it. (An `_exportId` that isn't one of the\nflow's page generators is the 400.)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get per-stage detail for a flow test-run step

> Returns the per-stage input, output, and errors captured for a single\
> step of a flow test run. Each step runs through one or more named\
> \*\*stages\*\* (e.g. \`request\`, \`parse\`, \`input\`, \`router\`); this endpoint\
> returns the ordered \`stages\[]\` for the requested step plus a top-level\
> \`errors\` array aggregating any step-level errors.\
> \
> The \`runId\` is the \`flowJob.\_id\` from the \`POST /v1/flows/{\_id}/test/run\`\
> response — test runs keep a separate history from production Job records.\
> \`{\_stepId}\` is one of the step ids from that response's \`metadata\` map;\
> the stage names returned here match the stage list that map recorded for\
> the step.\
> \
> For each stage, \`input\` and \`output\` are arrays of record envelopes\
> (\`{record, errors, traceKey}\`) and may be \`null\` when the stage produced\
> no records on that side. Use\
> \`GET /v1/flows/{\_id}/test/run/{runId}/{\_stepId}/logs/requestAndResponse\`\
> when you need the raw outbound HTTP request/response captures instead of\
> the staged record view.\
> \
> \*\*Endpoint template applies across three resource families.\*\* The same\
> path shape also exists for Tools (\`/v1/tools/{\_id}/test/run/{runId}/{\_stepId}\`)\
> and builder-mode APIs (\`/v1/apis/{\_id}/test/run/{runId}/{\_stepId}\`).\
> \
> Test-run state is short-lived and ephemeral — read step detail soon after\
> the run completes.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flows/{_id}/test/run/{runId}/{_stepId}":{"get":{"operationId":"getFlowTestRunStep","tags":["Flows"],"summary":"Get per-stage detail for a flow test-run step","description":"Returns the per-stage input, output, and errors captured for a single\nstep of a flow test run. Each step runs through one or more named\n**stages** (e.g. `request`, `parse`, `input`, `router`); this endpoint\nreturns the ordered `stages[]` for the requested step plus a top-level\n`errors` array aggregating any step-level errors.\n\nThe `runId` is the `flowJob._id` from the `POST /v1/flows/{_id}/test/run`\nresponse — test runs keep a separate history from production Job records.\n`{_stepId}` is one of the step ids from that response's `metadata` map;\nthe stage names returned here match the stage list that map recorded for\nthe step.\n\nFor each stage, `input` and `output` are arrays of record envelopes\n(`{record, errors, traceKey}`) and may be `null` when the stage produced\nno records on that side. Use\n`GET /v1/flows/{_id}/test/run/{runId}/{_stepId}/logs/requestAndResponse`\nwhen you need the raw outbound HTTP request/response captures instead of\nthe staged record view.\n\n**Endpoint template applies across three resource families.** The same\npath shape also exists for Tools (`/v1/tools/{_id}/test/run/{runId}/{_stepId}`)\nand builder-mode APIs (`/v1/apis/{_id}/test/run/{runId}/{_stepId}`).\n\nTest-run state is short-lived and ephemeral — read step detail soon after\nthe run completes.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"runId","in":"path","required":true,"description":"Test run id (`flowJob._id`) from the\n`POST /v1/flows/{_id}/test/run` response. Distinct from flow-run Job ids.","schema":{"type":"string"}},{"name":"_stepId","in":"path","required":true,"description":"Step id whose staged detail you want. One of the keys in the\ntest-run `metadata` map.","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-stage detail for the step. `stages[]` is the ordered list of\nstages the step ran; `errors` aggregates step-level errors.","content":{"application/json":{"schema":{"type":"object","description":"Staged detail for a single test-run step.","properties":{"stages":{"type":"array","description":"Ordered stages the step executed.","items":{"type":"object","description":"One stage of the step.","properties":{"name":{"type":"string","description":"Stage name (e.g. `request`, `parse`, `input`, `router`)."},"errors":{"description":"Errors raised during this stage, or `null` if none.","type":["array","null"],"items":{"type":"object","additionalProperties":true}},"input":{"description":"Input record envelopes for this stage, or `null` when\nthe stage produced no input side.","type":["array","null"],"items":{"type":"object","additionalProperties":true}},"output":{"description":"Output record envelopes for this stage, or `null` when\nthe stage produced no output side.","type":["array","null"],"items":{"type":"object","additionalProperties":true}}}}},"errors":{"type":"array","description":"Step-level errors aggregated across stages.","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get request/response logs for a flow test-run step

> Returns the outbound HTTP request/response log pairs captured during a\
> specific step of a flow test run. Only steps that issued outbound HTTP\
> calls (exports, imports, lookups) produce entries — routers, filters, and\
> other in-process stages are rejected with \`req\_res\_logs\_not\_found\` by\
> design.\
> \
> The \`runId\` comes from the \`POST /v1/flows/{\_id}/test/run\` response (not\
> from a normal flow run Job record — test runs and regular runs are\
> separate histories). \`{\_stepId}\` is the export or import id of the step\
> you want logs for; find the id among the keys in the test-run \`metadata\` map.\
> \
> \*\*Endpoint template applies across resource families.\*\* The same path shape\
> also exists for Tools (\`/v1/tools/{\_id}/test/run/.../logs/requestAndResponse\`)\
> and builder-mode APIs (\`/v1/apis/{\_id}/test/run/.../logs/requestAndResponse\`),\
> but response shapes differ by family: the builder-mode \*\*API\*\* variant returns\
> a \`{ requests: \[] }\` summary envelope whose entries are resolved via\
> \`GET /v1/apis/{\_id}/{\_stepId}/requests/{key}\`, rather than the array of\
> \`{ request, response }\` pairs documented here. Refer to each family's spec for\
> its exact response shape.\
> \
> Response entries may carry base64-encoded JSON in \`request.body\` and\
> \`response.body\` fields — decode string bodies before parsing. A 404\
> response is expected for non-HTTP steps (routers, filters); cross-check\
> against the test-run metadata's stage list before treating it as a\
> failure. Test runs are short-lived ephemeral state, so capture logs\
> soon after the run completes.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flows/{_id}/test/run/{runId}/{_stepId}/logs/requestAndResponse":{"get":{"operationId":"getFlowTestRunStepLogs","tags":["Flows"],"summary":"Get request/response logs for a flow test-run step","description":"Returns the outbound HTTP request/response log pairs captured during a\nspecific step of a flow test run. Only steps that issued outbound HTTP\ncalls (exports, imports, lookups) produce entries — routers, filters, and\nother in-process stages are rejected with `req_res_logs_not_found` by\ndesign.\n\nThe `runId` comes from the `POST /v1/flows/{_id}/test/run` response (not\nfrom a normal flow run Job record — test runs and regular runs are\nseparate histories). `{_stepId}` is the export or import id of the step\nyou want logs for; find the id among the keys in the test-run `metadata` map.\n\n**Endpoint template applies across resource families.** The same path shape\nalso exists for Tools (`/v1/tools/{_id}/test/run/.../logs/requestAndResponse`)\nand builder-mode APIs (`/v1/apis/{_id}/test/run/.../logs/requestAndResponse`),\nbut response shapes differ by family: the builder-mode **API** variant returns\na `{ requests: [] }` summary envelope whose entries are resolved via\n`GET /v1/apis/{_id}/{_stepId}/requests/{key}`, rather than the array of\n`{ request, response }` pairs documented here. Refer to each family's spec for\nits exact response shape.\n\nResponse entries may carry base64-encoded JSON in `request.body` and\n`response.body` fields — decode string bodies before parsing. A 404\nresponse is expected for non-HTTP steps (routers, filters); cross-check\nagainst the test-run metadata's stage list before treating it as a\nfailure. Test runs are short-lived ephemeral state, so capture logs\nsoon after the run completes.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"name":"runId","in":"path","required":true,"description":"Test run id from the `POST /v1/flows/{_id}/test/run` response.\nDistinct from flow-run Job ids.","schema":{"type":"string"}},{"name":"_stepId","in":"path","required":true,"description":"Export or import id of the step whose logs you want. Non-HTTP\nstages (routers, filters) 404 with `req_res_logs_not_found`.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Array of request/response log pairs captured during the step.\n`request.body` / `response.body` may be base64-encoded JSON.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"One request/response pair captured by the test engine.","properties":{"request":{"type":"object","description":"Outbound HTTP request envelope.","properties":{"method":{"type":"string","description":"HTTP method (e.g. `GET`, `POST`)."},"url":{"type":"string","description":"Fully-resolved request URL."},"headers":{"type":"object","description":"Request headers; sensitive values redacted server-side.","additionalProperties":true},"body":{"description":"Request body. Often **base64-encoded JSON** — decode\nbefore parsing. Empty for bodyless methods.","type":["string","null"]}}},"response":{"type":"object","description":"Remote response envelope.","properties":{"statusCode":{"type":"integer","description":"HTTP status code returned by the remote."},"headers":{"type":"object","description":"Response headers.","additionalProperties":true},"body":{"description":"Response body. Often **base64-encoded JSON** —\ndecode before parsing.","type":["string","null"]}}}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"Either the run/step id didn't resolve, or the step produced no\nrequest/response logs (non-HTTP stage — router, filter, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Cancel a flow execution group

> Cancels all remaining jobs in a flow execution group. Execution groups are created when multiple\
> flows are triggered together (e.g. via integration-level run or chained flows) and share a common\
> group identifier.\
> \
> The response varies depending on whether there were jobs left to cancel:\
> \- \*\*200\*\* with \`{"message": "No more jobs to cancel"}\` when no in-progress jobs remain.\
> \- \*\*204\*\* with no body when cancellation was successfully requested.\
> \
> This endpoint is not scoped to a specific flow — the \`\_id\` parameter is the execution group id,\
> not a flow id. Any string is accepted as the id (the server does not validate that the group\
> exists before responding).\
> \
> Unknown or already-completed group ids return 404 \`resource\_not\_found\` — only groups with\
> cancellable (queued/running) jobs are accepted.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/flowExecutionGroups/{_id}/cancel":{"put":{"operationId":"cancelFlowExecutionGroup","tags":["Flows"],"summary":"Cancel a flow execution group","description":"Cancels all remaining jobs in a flow execution group. Execution groups are created when multiple\nflows are triggered together (e.g. via integration-level run or chained flows) and share a common\ngroup identifier.\n\nThe response varies depending on whether there were jobs left to cancel:\n- **200** with `{\"message\": \"No more jobs to cancel\"}` when no in-progress jobs remain.\n- **204** with no body when cancellation was successfully requested.\n\nThis endpoint is not scoped to a specific flow — the `_id` parameter is the execution group id,\nnot a flow id. Any string is accepted as the id (the server does not validate that the group\nexists before responding).\n\nUnknown or already-completed group ids return 404 `resource_not_found` — only groups with\ncancellable (queued/running) jobs are accepted.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow execution group id.","schema":{"type":"string"}}],"responses":{"200":{"description":"No more jobs to cancel in the group.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Status message."}}}}}},"204":{"description":"Cancellation requested for remaining jobs in the group. No response body."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get static filter enum metadata for errors

> Returns the static enumeration values used to filter errors across the platform. The response\
> is not scoped to the authenticated user — every caller receives the same set of filter\
> dimensions and allowed values.\
> \
> Currently returns two filter dimensions:\
> \- \*\*source\*\* (24 values): \`internal\`, \`application\`, \`connection\`, \`resource\`,\
> &#x20; \`transformation\`, \`output\_filter\`, \`input\_filter\`, \`import\_filter\`, \`lookup\`, \`mapping\`,\
> &#x20; \`response\_mapping\`, \`pre\_save\_page\_hook\`, \`pre\_parse\_hook\`, \`pre\_map\_hook\`, \`post\_map\_hook\`,\
> &#x20; \`post\_submit\_hook\`, \`post\_response\_map\_hook\`, \`post\_aggregate\_hook\`, \`pre\_send\_hook\_ss\`,\
> &#x20; \`pre\_map\_hook\_ss\`, \`post\_map\_hook\_ss\`, \`post\_submit\_hook\_ss\`, \`tool\_input\`, \`tool\_output\`.\
> \- \*\*classification\*\* (10 values): \`connection\`, \`duplicate\`, \`governance\`, \`intermittent\`,\
> &#x20; \`missing\`, \`parse\`, \`value\`, \`rate\_limit\`, \`too\_large\`, \`none\`.\
> \
> The values are static and identical for all callers — cache them aggressively.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ErrorsFilterMetadataResponse":{"type":"object","description":"Static enumeration metadata for error filters. Returned by `GET /v1/errors/filterMetadata`.\nValues are not scoped to the authenticated user — the same set is returned for every caller.","properties":{"filters":{"type":"array","description":"Available filter dimensions with their allowed enum values.","items":{"type":"object","properties":{"name":{"type":"string","description":"Filter field name (e.g. `source`, `classification`)."},"enums":{"type":"array","description":"Allowed values for this filter dimension.","items":{"type":"string"}}}}}}}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/errors/filterMetadata":{"get":{"operationId":"getErrorsFilterMetadata","tags":["Flows"],"summary":"Get static filter enum metadata for errors","description":"Returns the static enumeration values used to filter errors across the platform. The response\nis not scoped to the authenticated user — every caller receives the same set of filter\ndimensions and allowed values.\n\nCurrently returns two filter dimensions:\n- **source** (24 values): `internal`, `application`, `connection`, `resource`,\n  `transformation`, `output_filter`, `input_filter`, `import_filter`, `lookup`, `mapping`,\n  `response_mapping`, `pre_save_page_hook`, `pre_parse_hook`, `pre_map_hook`, `post_map_hook`,\n  `post_submit_hook`, `post_response_map_hook`, `post_aggregate_hook`, `pre_send_hook_ss`,\n  `pre_map_hook_ss`, `post_map_hook_ss`, `post_submit_hook_ss`, `tool_input`, `tool_output`.\n- **classification** (10 values): `connection`, `duplicate`, `governance`, `intermittent`,\n  `missing`, `parse`, `value`, `rate_limit`, `too_large`, `none`.\n\nThe values are static and identical for all callers — cache them aggressively.","parameters":[],"responses":{"200":{"description":"Static filter metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorsFilterMetadataResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Preview the output of a flow's page processor

> Runs a flow's page generators and page processors through the preview\
> pipeline and returns the record arriving at one page-processor node,\
> with the upstream chain applied server-side. A target IMPORT obeys its\
> map entry's options flag: \`{preview: true}\` composes the request\
> without sending; \`{sendAndPreview: true}\` (the import editor's "Send"\
> button) executes it against the live destination — a real write — and\
> stops at the parsed response (the target's postSubmit hook does not\
> run). Both composing modes serve HTTP import targets only: a NetSuite,\
> Salesforce, RDBMS or FTP target answers \`422 no\_data\_available\` ("You\
> must add at least one mock input record…") whatever records the chain\
> delivers — the generic "no record reached the target", not a data\
> problem; execute such a step as a virtual import instead\
> (\`POST /v1/connections/{\_id}/import\`). No options flag returns the\
> arriving record for any adaptor without touching the target.\
> \
> Upstream behavior: the source export executes live (transform, output\
> filter and preSavePage hook applied); router branch filters and step\
> input filters gate the records; upstream lookups execute live unless a\
> saved \`mockOutput\` is present (a saved mock always wins); upstream\
> imports are NEVER executed — each substitutes its saved \`mockResponse\`,\
> or a platform placeholder when none is saved, before its response\
> mapping and postResponseMap hook run. A target LOOKUP executes its\
> live query even when it carries a saved \`mockOutput\` (the mock\
> substitutes only upstream). When a target import's \`failPath\` rules\
> judge the destination's answer a failure, the response is \`422\` whose\
> \`errors\[]\` carry \`source: application\` and \`stage: apiCall\` — the\
> request did execute. With \`includeStages: false\` the response is the\
> bare result object rather than the \`{data, stages}\` envelope.\
> \
> Body carries the flow shape plus resolved maps of page-generator and\
> page-processor docs keyed by \`\_id\`. The server uses those maps as the\
> source of truth for the preview — it does not read the persisted flow\
> doc, so callers can pass modified versions to "what-if" iterate.\
> \
> The body field is \`flow\` (the API's error message referencing \`flowDoc\`\
> is stale). Every entry referenced by \`flow\.pageGenerators\[].\_exportId\`\
> must exist in \`pageGeneratorMap\` keyed by that id, wrapped as\
> \`{doc, options}\`; same for \`pageProcessorMap\`. Set \`includeStages: true\`\
> to get the stage-by-stage diagnostic array. No job is created and no\
> flow state changes; live calls are limited to the source export,\
> un-mocked upstream lookups, the target lookup, and — only under\
> \`sendAndPreview\` — the target import. Upstream imports never call\
> out.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"PageProcessorsPreviewRequest":{"type":"object","description":"Flow-page-processor preview request. Carries the flow shape plus\nside-loaded maps of page-generator and page-processor docs so the\npreview engine can run without reading the persisted flow doc.","properties":{"flow":{"type":"object","description":"Flow document. Must at minimum carry `pageGenerators[]` and\n`pageProcessors[]` with `_exportId` / `_importId` references that\nmatch keys in the side-loaded maps. Full flow doc shape mirrors\n`POST /v1/flows` body. Accepted under key `flow` despite the\nserver's stale `flowDoc` error message.","properties":{"_selectedPageGeneratorId":{"type":"string","format":"objectId","description":"Page generator to drive the preview when the flow has multiple.\nDefaults to `pageGenerators[0]._exportId`. Set it inside `flow`: the\nserver ignores a top-level `_selectedPageGeneratorId`."}},"additionalProperties":true},"_pageProcessorId":{"type":"string","format":"objectId","description":"The pageProcessor resource id to preview. Must be present as a key\nin `pageProcessorMap`."},"pageGeneratorMap":{"type":"object","description":"Map of page-generator `_id` → `{doc, options}`. `doc` is the full\nexport doc for that generator; `options` is a preview-time hints\nobject (typically `{}` or `{preview: true}`).","additionalProperties":{"type":"object","properties":{"doc":{"type":"object","additionalProperties":true},"options":{"type":"object","additionalProperties":true}}}},"pageProcessorMap":{"type":"object","description":"Map of page-processor `_id` → `{doc, options}`. Shape matches\n`pageGeneratorMap`. The target entry's `options` flag selects the\npreview mode for a target IMPORT: `{preview: true}` (the import\neditor's \"Preview request\" button) composes the request and\nreturns it WITHOUT sending — the response carries a `request`\nstage only; `{sendAndPreview: true}` (the editor's \"Send\" button)\nEXECUTES the request against the live destination and returns\n`request`, `raw`, and `parse` stages with the real response.\nThe target entry's `options.inputData` (array of records) supplies\nthe mock input the editor's \"Mock input\" pane would provide.\nUpstream entries carry `{}`.\nRequest composition is adaptor-gated: the `preview`/`sendAndPreview`\nmodes work for HTTP, REST, and GraphQL import targets — a NetSuite,\nSalesforce, RDBMS or FTP import target fails with\n`422 no_data_available` regardless of supplied input (those\nadaptors have no request-preview surface; only the no-flag\ninput-data preview works for them, and the virtual import\n`POST /v1/connections/{_id}/import` executes them).","additionalProperties":{"type":"object","properties":{"doc":{"type":"object","additionalProperties":true},"options":{"type":"object","additionalProperties":true}}}},"includeStages":{"type":"boolean","description":"Include stage-by-stage diagnostics (`stages[]`) in the response.\nRecommended — without it the response loses the per-stage data and\nerror breakdown. When false, the preview instead behaves as an\ninput-data preview: the flow is stripped before the target step and\nthe response carries the records the target would receive as input\n(for a lookup step, with its `responseMapping` already merged in)."}},"required":["flow","_pageProcessorId","pageGeneratorMap","pageProcessorMap"]},"ExportPreviewResponse":{"type":"object","description":"Envelope returned by `POST /v1/exports/preview` (and the scoped\n`/v1/integrations/{_integrationId}/flows/{_flowId}/exports/preview`\nvariant). Carries per-stage diagnostics alongside the sampled records.","properties":{"data":{"type":"array","description":"Final sampled records produced by the preview — the output of the last\nstage, without the wrappers the transform, filter and hook stages put\naround it, so records the export's output filter dropped are not here.\nAbsent from the zero-record answers described under `stages`.","items":{}},"dataURIs":{"type":"array","description":"URIs for any files produced by the preview (e.g. file-based exports\nwriting to cloud storage). Empty for non-file adaptors.","items":{"type":"string"}},"dataRecordTraceKeys":{"type":"array","description":"Trace keys for the records in this preview — one per record,\ncorrelating stage outputs to their source record.","items":{"type":"string"}},"stages":{"type":"array","description":"Ordered list of pipeline stages the preview traversed. The preview\nruns the export's pipeline, not just the parse: `request` and `raw`\nfor HTTP exports; `parse` for a live read that returned records, and\nas the only stage when a `mockOutput` in the request body answers;\n`group` when the export groups records (grouped records are bare\narrays of the grouped rows). After a live `parse`, the stages the\nexport configures follow: the transform (`transformTwoDotZero` for\nTransformation 2.0 rules, `transform` for version 1 rules), the\noutput filter (`outputFilter`, where each record it drops carries\n`isIgnored: true`) and the preSavePage hook (`preSavePageHook`, which\nreceives only the records the filter kept). Top-level `data` holds\nthe records the last of them kept, unwrapped. Each stage carries its `data[]`\noutput and any `errors[]` raised at that stage. A live read that\nselects no records has been observed without a `parse` stage or\ntop-level `data` on two adaptors: an HTTP export returns only `request`\nand `raw`, and a NetSuite RESTlet search returns an empty object. Treat\nthose as zero records, not as a failed preview.","items":{"type":"object","description":"One pipeline stage's diagnostic and output envelope.","properties":{"name":{"type":"string","description":"Stage identifier (e.g. `request`, `raw`, `parse`, `transformTwoDotZero`, `outputFilter`, `preSavePageHook`)."},"data":{"description":"Stage output. Shape varies — `raw` carries the source\nresponse, `parse` (and `group`) carry the extracted records.\nThe transform and `outputFilter` stages carry one\n`{data, errors}` entry per record (a dropped record adds\n`isIgnored: true`), and `preSavePageHook` one entry for the\npage: the object the hook returned.","oneOf":[{"title":"Array","type":"array","items":{}},{"title":"Object","type":"object","additionalProperties":true},{"title":"Null","type":"null"}]},"errors":{"type":["array","null"],"description":"Errors raised at this stage, or `null` when clean.","items":{"type":"object","additionalProperties":true}}}}},"errors":{"type":"array","description":"Top-level error aggregate — typically mirrors the first non-null\n`stages[].errors[]` entry. Often omitted entirely when the preview\nran clean; callers should treat `undefined` and `[]` as equivalent.","items":{"type":"object","additionalProperties":true}},"traceKeysDuplicate":{"type":"array","description":"Trace keys that collided during the preview — a diagnostic for\ntrace-key generation; rarely non-empty in practice.","items":{"type":"string"}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/pageProcessors/preview":{"post":{"operationId":"previewPageProcessor","tags":["Flows"],"summary":"Preview the output of a flow's page processor","description":"Runs a flow's page generators and page processors through the preview\npipeline and returns the record arriving at one page-processor node,\nwith the upstream chain applied server-side. A target IMPORT obeys its\nmap entry's options flag: `{preview: true}` composes the request\nwithout sending; `{sendAndPreview: true}` (the import editor's \"Send\"\nbutton) executes it against the live destination — a real write — and\nstops at the parsed response (the target's postSubmit hook does not\nrun). Both composing modes serve HTTP import targets only: a NetSuite,\nSalesforce, RDBMS or FTP target answers `422 no_data_available` (\"You\nmust add at least one mock input record…\") whatever records the chain\ndelivers — the generic \"no record reached the target\", not a data\nproblem; execute such a step as a virtual import instead\n(`POST /v1/connections/{_id}/import`). No options flag returns the\narriving record for any adaptor without touching the target.\n\nUpstream behavior: the source export executes live (transform, output\nfilter and preSavePage hook applied); router branch filters and step\ninput filters gate the records; upstream lookups execute live unless a\nsaved `mockOutput` is present (a saved mock always wins); upstream\nimports are NEVER executed — each substitutes its saved `mockResponse`,\nor a platform placeholder when none is saved, before its response\nmapping and postResponseMap hook run. A target LOOKUP executes its\nlive query even when it carries a saved `mockOutput` (the mock\nsubstitutes only upstream). When a target import's `failPath` rules\njudge the destination's answer a failure, the response is `422` whose\n`errors[]` carry `source: application` and `stage: apiCall` — the\nrequest did execute. With `includeStages: false` the response is the\nbare result object rather than the `{data, stages}` envelope.\n\nBody carries the flow shape plus resolved maps of page-generator and\npage-processor docs keyed by `_id`. The server uses those maps as the\nsource of truth for the preview — it does not read the persisted flow\ndoc, so callers can pass modified versions to \"what-if\" iterate.\n\nThe body field is `flow` (the API's error message referencing `flowDoc`\nis stale). Every entry referenced by `flow.pageGenerators[]._exportId`\nmust exist in `pageGeneratorMap` keyed by that id, wrapped as\n`{doc, options}`; same for `pageProcessorMap`. Set `includeStages: true`\nto get the stage-by-stage diagnostic array. No job is created and no\nflow state changes; live calls are limited to the source export,\nun-mocked upstream lookups, the target lookup, and — only under\n`sendAndPreview` — the target import. Upstream imports never call\nout.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageProcessorsPreviewRequest"}}}},"responses":{"200":{"description":"Preview envelope. Mirrors `ExportPreviewResponse` — `stages[]` carries\nthe stage-by-stage output + errors, and the top-level `errors[]`\naggregates any configuration failures surfaced during the run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportPreviewResponse"}}}},"400":{"description":"Request structural errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"description":"Two distinct meanings, told apart by `errors[].source`:\n`no_data_available` with `source: integrator` — no record reached\nthe target in a composing mode (the target is a NetSuite,\nSalesforce, RDBMS or FTP import, which these modes cannot drive, or\nthe chain's gates dropped every record); `source: application` with\n`stage: apiCall` after `sendAndPreview` — the request DID execute\nand the target import's `failPath` rules judged the destination's\nanswer a failure; `message` carries the destination's response body\nand `code` its HTTP status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## List dependencies of a flow

> Returns the set of resources that depend on the specified resource.\
> The response is an object whose keys are dependent-resource types\
> (e.g. \`flows\`, \`imports\`) and whose values are arrays of dependency\
> entries.\
> \
> An empty object \`{}\` means no other resources depend on the target — this is also returned for a\
> well-formatted but nonexistent id.

```json
{"openapi":"3.2.0","info":{"title":"Flows","version":"1.0.0"},"tags":[{"name":"Flows","description":"Flows orchestrate how data moves between systems. A flow chains one or more page\ngenerators (exports that produce records) into a pipeline of page processors (lookups\nand imports), with optional routers for conditional branching. Flows run on a cron\nschedule, on demand, or in response to real-time events, and expose endpoints for\nrunning, monitoring, and managing per-step errors.\n\n## Flow schema\n\n{% openapi-schemas spec=\"flow\" schemas=\"Flow\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"DependencyResponse":{"type":"object","description":"Map of dependent-resource types to arrays of dependency entries.\nKeys are plural resource type strings (e.g. `flows`, `imports`,\n`connections`). An empty object `{}` means no dependents.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/DependencyEntry"}}},"DependencyEntry":{"type":"object","description":"A single resource that depends on the queried resource.","properties":{"id":{"type":"string","description":"Unique identifier of the dependent resource."},"name":{"type":"string","description":"Display name of the dependent resource."},"type":{"type":"string","description":"Sub-type of the dependent resource when its collection distinguishes one, such as\n`stream` for a listener export. Only present for resource types that carry a `type`."},"paths":{"type":"array","description":"Dot-notation paths within the dependent resource that reference\nthe target resource. `[*]` denotes array elements.","items":{"type":"string"}},"accessLevel":{"type":"string","description":"The caller's access level on the dependent resource."},"dependencyIds":{"type":"object","description":"Map of resource types to arrays of IDs that this dependent\nresource references on the target. Keys are singular or plural\nresource type strings; values are arrays of ID strings.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["id","name","paths","accessLevel","dependencyIds"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/flows/{_id}/dependencies":{"get":{"operationId":"listFlowDependencies","tags":["Flows"],"summary":"List dependencies of a flow","description":"Returns the set of resources that depend on the specified resource.\nThe response is an object whose keys are dependent-resource types\n(e.g. `flows`, `imports`) and whose values are arrays of dependency\nentries.\n\nAn empty object `{}` means no other resources depend on the target — this is also returned for a\nwell-formatted but nonexistent id.","parameters":[{"name":"_id","in":"path","required":true,"description":"Resource ID.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Dependency map. Keys are resource-type strings; values are arrays\nof dependency entries. Returns `{}` when no dependents exist.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DependencyResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```
