> 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/monitoring/jobs.md).

# Jobs

Jobs are read-only records of flow, export, and import executions, created by the platform whenever a run occurs. A parent flow job aggregates the run's counters while child export/import jobs carry per-step counts, errors, and artifacts. Use these endpoints to monitor running jobs, inspect job families, download result files, and cancel or purge runs.

### Job schema

## The Job object

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"components":{"schemas":{"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"]}}}}}}
```

## List all jobs

> Returns jobs matching the given query-parameter filters, up to 1001 per\
> page in descending \`createdAt\` order. Use \`createdAt\_lte\` on the last\
> record's \`createdAt\` (minus 1 ms) to page forward.\
> \
> There are two query modes depending on the \`type\` parameter:\
> \
> \- \*\*Parent jobs\*\* (\`type\` omitted, \`flow\`, \`retry\`, or \`bulk\_retry\`) —\
> &#x20; pass at least one of \`\_integrationId\`, \`\_flowId\`, \`\_exportId\`,\
> &#x20; \`\_importId\`, \`\_flowJobId\`, \`createdAt\_gte\`, or \`createdAt\_lte\` to\
> &#x20; scope the query. Omitting all filters returns all jobs in the account.\
> &#x20; Exception: for a caller with integration-only access, \`\_flowId\` scopes\
> &#x20; a \`type=flow\` or \`type=retry\` query only together with\
> &#x20; \`\_integrationId\` (below).\
> \- \*\*Child jobs\*\* (\`type=export\` or \`type=import\`) — requires\
> &#x20; \`\_flowJobId\` or a resource ID filter (\`\_exportId\` / \`\_importId\`).\
> &#x20; Returns the export/import sub-jobs within a parent flow job.\
> \
> Job reads are authorized per integration. For a caller with\
> integration-only access (an account share that populates\
> \`integrationAccessLevel\` and omits \`accessLevel\`), a parent-job query\
> scoped by \`\_flowId\` alone (\`type=flow\` or \`type=retry\`) fails with \`400\`\
> \`query\_param\_required\` ("Please provide the integration \_id for which you\
> want to fetch the jobs"); it succeeds once \`\_integrationId\` is sent beside\
> \`\_flowId\`. Account-level callers may scope by \`\_flowId\` alone, but that\
> path resolves the flow document first, so the jobs of a deleted flow come\
> back only when \`\_integrationId\` is sent. Send the flow's \`\_integrationId\`\
> together with \`\_flowId\` whenever the flow document carries one — a flow\
> in the account's "Standalone flows" integration sends that integration's\
> id; only a legacy flow whose \`\_integrationId\` is \`null\` has none to send.\
> \
> Date filters accept ISO 8601, plain date, or epoch milliseconds. When\
> combining \`numError\_gte\`/\`numError\_lte\` with \`\_integrationId\`, use full\
> ISO 8601 with millis (plain-date format may be rejected). To page\
> forward, take the \`createdAt\` of the last record, subtract 1 ms, and\
> pass it as \`createdAt\_lte\`.\
> \
> A \`queued\` or \`running\` job created outside \`createdAt\_gte\` /\
> \`createdAt\_lte\` is left out of a date-filtered list.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"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":{"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/jobs":{"get":{"operationId":"listJobs","tags":["Jobs"],"summary":"List all jobs","description":"Returns jobs matching the given query-parameter filters, up to 1001 per\npage in descending `createdAt` order. Use `createdAt_lte` on the last\nrecord's `createdAt` (minus 1 ms) to page forward.\n\nThere are two query modes depending on the `type` parameter:\n\n- **Parent jobs** (`type` omitted, `flow`, `retry`, or `bulk_retry`) —\n  pass at least one of `_integrationId`, `_flowId`, `_exportId`,\n  `_importId`, `_flowJobId`, `createdAt_gte`, or `createdAt_lte` to\n  scope the query. Omitting all filters returns all jobs in the account.\n  Exception: for a caller with integration-only access, `_flowId` scopes\n  a `type=flow` or `type=retry` query only together with\n  `_integrationId` (below).\n- **Child jobs** (`type=export` or `type=import`) — requires\n  `_flowJobId` or a resource ID filter (`_exportId` / `_importId`).\n  Returns the export/import sub-jobs within a parent flow job.\n\nJob reads are authorized per integration. For a caller with\nintegration-only access (an account share that populates\n`integrationAccessLevel` and omits `accessLevel`), a parent-job query\nscoped by `_flowId` alone (`type=flow` or `type=retry`) fails with `400`\n`query_param_required` (\"Please provide the integration _id for which you\nwant to fetch the jobs\"); it succeeds once `_integrationId` is sent beside\n`_flowId`. Account-level callers may scope by `_flowId` alone, but that\npath resolves the flow document first, so the jobs of a deleted flow come\nback only when `_integrationId` is sent. Send the flow's `_integrationId`\ntogether with `_flowId` whenever the flow document carries one — a flow\nin the account's \"Standalone flows\" integration sends that integration's\nid; only a legacy flow whose `_integrationId` is `null` has none to send.\n\nDate filters accept ISO 8601, plain date, or epoch milliseconds. When\ncombining `numError_gte`/`numError_lte` with `_integrationId`, use full\nISO 8601 with millis (plain-date format may be rejected). To page\nforward, take the `createdAt` of the last record, subtract 1 ms, and\npass it as `createdAt_lte`.\n\nA `queued` or `running` job created outside `createdAt_gte` /\n`createdAt_lte` is left out of a date-filtered list.","parameters":[{"name":"_integrationId","in":"query","schema":{"type":"string"},"description":"Filter by integration ID. Satisfies the required-param check. Callers\nwith integration-only access must send it beside `_flowId` on\n`type=flow` and `type=retry` queries — `_flowId` alone is refused\nthere. A value that is not the flow's integration returns no jobs\nrather than an error."},{"name":"_exportId","in":"query","schema":{"type":"string"},"description":"Filter by export ID. Satisfies the required-param check."},{"name":"_importId","in":"query","schema":{"type":"string"},"description":"Filter by import ID. Satisfies the required-param check."},{"name":"_flowId","in":"query","schema":{"type":"string"},"description":"Filter by flow ID. Satisfies the required-param check for\naccount-level callers; callers with integration-only access must\nalso send `_integrationId` on `type=flow` and `type=retry` queries.\nOn its own it resolves the flow document\nfirst, so it returns nothing for a flow that no longer exists — pair\nit with `_integrationId` to read a deleted flow's jobs."},{"name":"_flowJobId","in":"query","schema":{"type":"string"},"description":"Filter by parent flow-job ID. Satisfies the required-param check.\nRequired when querying child jobs (`type=export` or `type=import`)."},{"name":"_flowId_in","in":"query","schema":{"type":"string"},"description":"Comma-separated list of flow IDs to match. Works as an additional\nfilter but does **not** satisfy the required-param check alone.\n`flowId_in` (without underscore) is accepted as an alias."},{"name":"status_in","in":"query","schema":{"type":"string"},"description":"Comma-separated list of status values to match (e.g.\n`completed,failed`). Works as an additional filter but does\n**not** satisfy the required-param check alone."},{"name":"createdAt_lte","in":"query","schema":{"type":"string"},"description":"Return jobs created at or before this timestamp. Accepts ISO 8601,\nplain date, or epoch milliseconds. Satisfies the required-param\ncheck."},{"name":"createdAt_gte","in":"query","schema":{"type":"string"},"description":"Return jobs created at or after this timestamp. Accepts ISO 8601,\nplain date, or epoch milliseconds. Satisfies the required-param\ncheck."},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","running","completed","failed","canceled","canceling","retrying"]},"description":"Filter by job status."},{"name":"numSuccess_lte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with success count ≤ this value."},{"name":"numSuccess_gte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with success count ≥ this value."},{"name":"numIgnore_lte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with ignore count ≤ this value."},{"name":"numIgnore_gte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with ignore count ≥ this value."},{"name":"numError_gte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with error count ≥ this value. When combined with\n`_integrationId`, the query may reject plain-date `createdAt`\nvalues — use full ISO 8601."},{"name":"numError_lte","in":"query","schema":{"type":"integer"},"description":"Filter to jobs with error count ≤ this value. Same date-format\ncaveat as `numError_gte`."},{"name":"type","in":"query","schema":{"type":"string","enum":["flow","export","import","retry","bulk_retry"]},"description":"Filter by job type. `flow`, `retry`, and `bulk_retry` are\nparent-level jobs; `export` and `import` are child jobs (require\n`_flowJobId` or a resource-ID filter). Unrecognized values silently\nreturn an empty response."}],"responses":{"200":{"description":"Array of job records matching the filters.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}}},"204":{"description":"No jobs match the given filters."},"400":{"description":"Required query parameters are missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"description":"A query parameter the listing does not support; the message names it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## List in-progress jobs (dashboard)

> Returns a paginated list of currently in-progress jobs for the dashboard -- jobs whose \`status\` is one of\
> \`queued\`, \`running\`, or \`canceling\`. Jobs that have reached a terminal state (\`completed\`, \`failed\`,\
> \`canceled\`, \`retried\`) are not returned; use \`POST /v1/flows/runs/stats\` for run history.\
> \
> The request body contains all filters -- there are no query-string parameters. Narrow to a specific flow or\
> integration with \`\_flowIds\` / \`\_integrationIds\` (not both — sending both is rejected with HTTP 400).\
> \`time\_gt\` and \`time\_lte\` are not filters on this endpoint; use \`POST /v1/flows/runs/stats\`. To find\
> long-running jobs, compare each job's \`createdAt\` or \`startedAt\` on the client.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"JobsCurrentRequest":{"type":"object","description":"Request body for `POST /v1/jobs/current`.\nThe UI uses this to fetch in-progress jobs for the dashboard.\n","properties":{"_integrationIds":{"type":"array","description":"Optional filter to only return jobs for these integration ids.","items":{"type":"string","format":"objectId"}},"_flowIds":{"type":"array","description":"Optional filter to only return jobs for these flow ids.","items":{"type":"string","format":"objectId"}},"status":{"type":"array","description":"Optional filter for in-progress job statuses.\nTerminal statuses (`completed`, `failed`, `canceled`, `retried`) are rejected with HTTP 400 by this endpoint —\nuse `POST /v1/flows/runs/stats` for completed-run history.\n","items":{"type":"string","enum":["queued","running","canceling"]}},"applicationIds":{"type":"array","description":"Optional filter by application ids.","items":{"type":"string"}},"createdOnAndAfter":{"type":"string","format":"date-time","description":"Paging cursor. The server sets this on `pagingPostBody` to the last row's `createdAt`."}},"required":[]},"JobsCurrentResponse":{"type":"object","description":"Response envelope for `POST /v1/jobs/current`.","properties":{"jobs":{"type":"array","description":"Current (in-progress) jobs.","items":{"$ref":"#/components/schemas/CurrentJobEntry"}},"pagingPostBody":{"description":"Cursor for the next page. Absent on the last (or only) page. Pagination is **body-based**:\nPOST this object back to the same endpoint as the next request body to fetch the next page.\nEchoes the caller's filter plus a server-added watermark (`createdOnAndAfter`). Single-page\nresponses omit this field entirely.","allOf":[{"$ref":"#/components/schemas/JobsCurrentRequest"}]}}},"CurrentJobEntry":{"allOf":[{"$ref":"#/components/schemas/Job"},{"type":"object","properties":{"flow":{"$ref":"#/components/schemas/DashboardFlow"}}}]},"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"]}}},"DashboardFlow":{"type":"object","description":"Minimal flow metadata inlined for rendering convenience — equivalent to `GET /v1/flows/{_flowId}` with most fields stripped.","properties":{"_id":{"type":"string","format":"objectId","description":"Flow id (matches the outer `_flowId`)."},"name":{"type":"string","description":"Flow name."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance was created from. Omitted for ordinary flows."},"abstractFlowName":{"type":"string","description":"Name of the abstract flow. Omitted when `_abstractFlowId` is absent."},"_integrationId":{"type":"string","format":"objectId","description":"Parent integration id. Omitted for standalone flows."},"integrationName":{"type":"string","description":"Parent integration name. Omitted for standalone flows."}}},"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/jobs/current":{"post":{"operationId":"listCurrentJobs","tags":["Jobs"],"summary":"List in-progress jobs (dashboard)","description":"Returns a paginated list of currently in-progress jobs for the dashboard -- jobs whose `status` is one of\n`queued`, `running`, or `canceling`. Jobs that have reached a terminal state (`completed`, `failed`,\n`canceled`, `retried`) are not returned; use `POST /v1/flows/runs/stats` for run history.\n\nThe request body contains all filters -- there are no query-string parameters. Narrow to a specific flow or\nintegration with `_flowIds` / `_integrationIds` (not both — sending both is rejected with HTTP 400).\n`time_gt` and `time_lte` are not filters on this endpoint; use `POST /v1/flows/runs/stats`. To find\nlong-running jobs, compare each job's `createdAt` or `startedAt` on the client.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobsCurrentRequest"}}}},"responses":{"200":{"description":"One page of in-progress jobs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobsCurrentResponse"}}}},"204":{"description":"No in-progress jobs match the filter."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Get per-flow run statistics (dashboard aggregates)

> Returns \*\*per-flow aggregate\*\* run statistics — one element of \`stats\[]\` per flow that has at least\
> one run matching the request filter. Each aggregate carries totals (\`numRuns\`, \`numSuccess\`,\
> \`numError\`, \`numIgnore\`), the currently-open error count (\`numOpenError\`), resolution attribution\
> (\`numResolvedByAuto\` / \`numResolvedByUser\`), average runtime (\`avgRuntime\`), and timestamps\
> (\`lastExecutedAt\`, \`lastErrorAt\`) plus a minimal inlined \`flow{}\` object for rendering.\
> \
> The Celigo dashboard uses this to paint its "All flows" summary in one call. Filters (\`\_flowIds\`,\
> \`\_integrationIds\`, \`time\_gt\`, \`time\_lte\`, …) narrow which runs are rolled up into each aggregate —\
> they do \*\*not\*\* filter which flows appear; flows with zero matching runs are simply omitted.\
> \
> \*\*The window is the contract.\*\* When \`time\_gt\` is omitted the endpoint applies its default\
> window (approximately the last 24 hours) rather than aggregating all history — runs older than\
> the window silently drop out of every aggregate. Send \`time\_gt\` explicitly for any other range.\
> \
> For individual job records rather than aggregates, use \`GET /v1/jobs?\_flowId=...\`. For in-progress\
> jobs, use \`POST /v1/jobs/current\`.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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","description":"Request body for `POST /v1/flows/runs/stats`. Shares common filters with `POST /v1/jobs/current`\n(`_integrationIds`, `_flowIds`, …), but the response is a set of\n**per-flow aggregates** rather than individual job records. Filters narrow which runs are rolled\nup into each aggregate.\n\nOmitting `time_gt` does not mean \"all history\" — the endpoint falls back to the dashboard's\ndefault window (approximately the last 24 hours), and runs older than that silently drop out\nof every aggregate. Send `time_gt` (epoch milliseconds) explicitly for any other range.\n\n`time_lte` must not be later than the current time: a future value is rejected with\n`400 invalid_filter_request_body`. Omit\n`time_lte` to end the window at now. When both bounds are sent they must be at least one hour\napart (`time_lte - time_gt >= 3600000`), or the request is rejected with\n`400 invalid_time_filter`; a window with `time_gt` alone has no minimum span.","properties":{"_integrationIds":{"type":"array","description":"Optional filter to only return jobs for these integration ids.","items":{"type":"string","format":"objectId"}},"_flowIds":{"type":"array","description":"Optional filter to only return jobs for these flow ids.","items":{"type":"string","format":"objectId"}},"applicationIds":{"type":"array","description":"Optional filter by application ids.","items":{"type":"string"}},"category":{"type":"string","description":"Optional category filter (e.g., `edi`)."},"time_gt":{"type":"integer","format":"int64","description":"Start of the time window, in epoch milliseconds (exclusive). `POST /v1/flows/runs/stats`\naggregates only runs inside the window."},"time_lte":{"type":"integer","format":"int64","description":"End of the time window, in epoch milliseconds (inclusive). `POST /v1/flows/runs/stats`\naggregates only runs inside the window."},"endedOnOrBefore":{"type":"string","format":"date-time","description":"Paging cursor. The server sets this on `pagingPostBody` to the last row's `lastExecutedAt`."}},"required":[]},"FlowRunsStatsResponse":{"type":"object","description":"One page of per-flow run-statistics aggregates. Despite the endpoint's location under `flows/runs/`,\neach element of `stats[]` is **not** an individual job record — it's the aggregated summary for one\nflow across all matching runs (counts, timings, and the most recent timestamps). The dashboard uses\nthis to render its per-flow \"last run / success rate / open errors\" cards in a single call.\n\nTo list individual job records (one per run), use `GET /v1/jobs?_flowId=...` instead.","properties":{"stats":{"type":"array","description":"Per-flow aggregate entries. One element per flow that has at least one run matching the request\nfilter.","items":{"$ref":"#/components/schemas/FlowRunStatsEntry"}},"pagingPostBody":{"description":"Cursor for the next page. Absent on the last (or only) page. Pagination is **body-based**:\nPOST this object back to the same endpoint as the next request body to fetch the next page.\nThe object echoes the caller's filter plus a server-added watermark\n(`endedOnOrBefore`) that carries the cursor position. Single-page responses (typical for\nnormal account sizes) omit this field entirely.","allOf":[{"$ref":"#/components/schemas/FlowRunsStatsRequest"}]}}},"FlowRunStatsEntry":{"type":"object","description":"Per-flow aggregate across all matching runs. Produced by `POST /v1/flows/runs/stats` and used to\npopulate the Celigo dashboard's per-flow summary cards.","properties":{"_flowId":{"type":"string","format":"objectId","description":"Id of the flow this entry aggregates."},"_integrationId":{"type":"string","format":"objectId","description":"Id of the flow's parent integration. Omitted for standalone flows that aren't part of an\nintegration."},"numRuns":{"type":"integer","minimum":0,"description":"Total number of runs that matched the request filter."},"numPages":{"type":"integer","minimum":0,"description":"Total pages processed across those runs (one run can produce multiple pages when the source\nexport paginates)."},"numSuccess":{"type":"integer","minimum":0,"description":"Records that completed successfully across all matched runs."},"numError":{"type":"integer","minimum":0,"description":"Records that failed across all matched runs. Distinct from `numOpenError` — this is the\nlifetime-of-those-runs error count, not the currently-unresolved count."},"numIgnore":{"type":"integer","minimum":0,"description":"Records that were ignored (filtered out by `inputFilter` / `outputFilter`) across all matched runs."},"numOpenError":{"type":"integer","minimum":0,"description":"Currently **open** (unresolved) errors on this flow. Drops when errors are resolved or retried."},"numResolvedByAuto":{"type":"integer","minimum":0,"description":"Errors the platform resolved automatically."},"numResolvedByUser":{"type":"integer","minimum":0,"description":"Errors a user resolved."},"avgRuntime":{"type":"number","description":"Mean job runtime in milliseconds across matched runs."},"lastExecutedAt":{"type":"string","format":"date-time","description":"Timestamp of the most recent matching terminal run (`completed`, `canceled`, or `failed`)."},"lastErrorAt":{"type":"string","format":"date-time","description":"Timestamp of the most recent open error. Omitted when `numOpenError` is 0."},"flow":{"$ref":"#/components/schemas/DashboardFlow"}}},"DashboardFlow":{"type":"object","description":"Minimal flow metadata inlined for rendering convenience — equivalent to `GET /v1/flows/{_flowId}` with most fields stripped.","properties":{"_id":{"type":"string","format":"objectId","description":"Flow id (matches the outer `_flowId`)."},"name":{"type":"string","description":"Flow name."},"_abstractFlowId":{"type":"string","format":"objectId","description":"Abstract flow this instance was created from. Omitted for ordinary flows."},"abstractFlowName":{"type":"string","description":"Name of the abstract flow. Omitted when `_abstractFlowId` is absent."},"_integrationId":{"type":"string","format":"objectId","description":"Parent integration id. Omitted for standalone flows."},"integrationName":{"type":"string","description":"Parent integration name. Omitted for standalone flows."}}},"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/runs/stats":{"post":{"operationId":"getFlowRunsStats","tags":["Jobs"],"summary":"Get per-flow run statistics (dashboard aggregates)","description":"Returns **per-flow aggregate** run statistics — one element of `stats[]` per flow that has at least\none run matching the request filter. Each aggregate carries totals (`numRuns`, `numSuccess`,\n`numError`, `numIgnore`), the currently-open error count (`numOpenError`), resolution attribution\n(`numResolvedByAuto` / `numResolvedByUser`), average runtime (`avgRuntime`), and timestamps\n(`lastExecutedAt`, `lastErrorAt`) plus a minimal inlined `flow{}` object for rendering.\n\nThe Celigo dashboard uses this to paint its \"All flows\" summary in one call. Filters (`_flowIds`,\n`_integrationIds`, `time_gt`, `time_lte`, …) narrow which runs are rolled up into each aggregate —\nthey do **not** filter which flows appear; flows with zero matching runs are simply omitted.\n\n**The window is the contract.** When `time_gt` is omitted the endpoint applies its default\nwindow (approximately the last 24 hours) rather than aggregating all history — runs older than\nthe window silently drop out of every aggregate. Send `time_gt` explicitly for any other range.\n\nFor individual job records rather than aggregates, use `GET /v1/jobs?_flowId=...`. For in-progress\njobs, use `POST /v1/jobs/current`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunsStatsRequest"}}}},"responses":{"200":{"description":"One page of per-flow aggregates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunsStatsResponse"}}}},"204":{"description":"No runs match the filter on any flow within the queried window (the ~24-hour default when no `time_gt` was sent)."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Batch-fetch job families

> Returns job families for an array of job ids, in one request. Each item in the response array has the same\
> shape as a single \`GET /v1/jobs/{\_id}/family\` call (a parent job with inlined \`children\`).\
> \
> \*\*Size limit: 1000 ids per request.\*\* The server rejects requests with more than 1000 entries with HTTP\
> \*\*403\*\* (not 400) and \`{code: "invalid\_request", message: "Number of objects in the request exceeds\
> maximum allowed limit 1000"}\`. The Celigo UI chunks at 50 for its own UX reasons, but the API ceiling\
> is 1000.\
> \
> \*\*Mixed-id behavior (asymmetric):\*\*\
> \- Valid + unknown 24-hex ids in the same array → \*\*200\*\* with only the resolved entries; unknown ids are\
> &#x20; silently dropped (no \`errors\[]\` alongside).\
> \- All ids unknown → \*\*404\*\* with \`{errors: \[{code: "invalid\_ref", source: "internal", message: "Job not\
> &#x20; found: \<id>"}]}\`.\
> \- Any id that isn't a 24-char hex string anywhere in the array → \*\*400\*\* \`invalid\_ref "Please provide\
> &#x20; a valid \_id."\` — the whole request fails.\
> \- Duplicate ids are \*\*deduped\*\* server-side (same id ×N → one entry).\
> \- Empty array \`\[]\` or non-array body (e.g. \`{}\`) → \*\*400\*\* \`invalid\_request "Request body should be an\
> &#x20; ObjectID array."\`.\
> \- Missing \`Content-Type: application/json\` → \*\*415\*\* \`{message: "Content-Type should equal\
> &#x20; application/json"}\`.\
> \
> The response array has no guaranteed ordering; match items by \`\_id\` rather than by index. Unknown ids are\
> silently dropped -- callers that need to detect missing ids must diff the request and response id sets.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"JobsFamilyBatchRequest":{"type":"array","description":"Array of job ids to fetch family information for (max 1000 ids per request).","items":{"type":"string","format":"objectId"}},"JobWithChildren":{"allOf":[{"$ref":"#/components/schemas/Job"},{"type":"object","description":"Job plus any child jobs (job family view).","properties":{"children":{"type":"array","readOnly":true,"description":"Child jobs (export/import) that are part of this job family.","items":{"$ref":"#/components/schemas/Job"}}}}]},"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"]}}}},"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"}}}}}},"paths":{"/v1/jobs/family":{"post":{"operationId":"getJobFamilyBatch","tags":["Jobs"],"summary":"Batch-fetch job families","description":"Returns job families for an array of job ids, in one request. Each item in the response array has the same\nshape as a single `GET /v1/jobs/{_id}/family` call (a parent job with inlined `children`).\n\n**Size limit: 1000 ids per request.** The server rejects requests with more than 1000 entries with HTTP\n**403** (not 400) and `{code: \"invalid_request\", message: \"Number of objects in the request exceeds\nmaximum allowed limit 1000\"}`. The Celigo UI chunks at 50 for its own UX reasons, but the API ceiling\nis 1000.\n\n**Mixed-id behavior (asymmetric):**\n- Valid + unknown 24-hex ids in the same array → **200** with only the resolved entries; unknown ids are\n  silently dropped (no `errors[]` alongside).\n- All ids unknown → **404** with `{errors: [{code: \"invalid_ref\", source: \"internal\", message: \"Job not\n  found: <id>\"}]}`.\n- Any id that isn't a 24-char hex string anywhere in the array → **400** `invalid_ref \"Please provide\n  a valid _id.\"` — the whole request fails.\n- Duplicate ids are **deduped** server-side (same id ×N → one entry).\n- Empty array `[]` or non-array body (e.g. `{}`) → **400** `invalid_request \"Request body should be an\n  ObjectID array.\"`.\n- Missing `Content-Type: application/json` → **415** `{message: \"Content-Type should equal\n  application/json\"}`.\n\nThe response array has no guaranteed ordering; match items by `_id` rather than by index. Unknown ids are\nsilently dropped -- callers that need to detect missing ids must diff the request and response id sets.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobsFamilyBatchRequest"}}}},"responses":{"200":{"description":"An array of job families, one per **resolved** id (unknown ids silently dropped).","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/JobWithChildren"}}}}},"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"},"415":{"description":"Returned when the request is missing the `Content-Type: application/json` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get a job

> Returns a single job record. Works for both parent jobs (\`type=flow\`, \`retry\`, \`bulk\_retry\`) and child jobs\
> (\`type=export\`, \`type=import\`). For the full parent+children view of a flow run, use\
> \`GET /v1/jobs/{\_id}/family\` instead. For a multi-job lookup, use \`POST /v1/jobs/family\`.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"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":{"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/jobs/{_id}":{"get":{"operationId":"getJobById","tags":["Jobs"],"summary":"Get a job","description":"Returns a single job record. Works for both parent jobs (`type=flow`, `retry`, `bulk_retry`) and child jobs\n(`type=export`, `type=import`). For the full parent+children view of a flow run, use\n`GET /v1/jobs/{_id}/family` instead. For a multi-job lookup, use `POST /v1/jobs/family`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"The job record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"The `_id` is not a valid ObjectId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"No job exists with the given ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get a job and its children

> Returns a single job record (as parent) with all of its child jobs inlined under \`children\`.\
> \
> A "job family" maps to one flow execution: the parent is a \`type: "flow"\` job and the children are the\
> \`export\` / \`import\` / \`retry\` jobs that ran as part of it. For non-flow jobs (a standalone export run, or a\
> retry), \`children\` may be empty.\
> \
> For fetching many families at once, batch via \`POST /v1/jobs/family\`. The parent's counters may not include\
> bulk-retry jobs spawned after the initial run -- aggregate across \`children\` for an accurate per-run summary.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"JobWithChildren":{"allOf":[{"$ref":"#/components/schemas/Job"},{"type":"object","description":"Job plus any child jobs (job family view).","properties":{"children":{"type":"array","readOnly":true,"description":"Child jobs (export/import) that are part of this job family.","items":{"$ref":"#/components/schemas/Job"}}}}]},"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":{"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/jobs/{_id}/family":{"get":{"operationId":"getJobFamily","tags":["Jobs"],"summary":"Get a job and its children","description":"Returns a single job record (as parent) with all of its child jobs inlined under `children`.\n\nA \"job family\" maps to one flow execution: the parent is a `type: \"flow\"` job and the children are the\n`export` / `import` / `retry` jobs that ran as part of it. For non-flow jobs (a standalone export run, or a\nretry), `children` may be empty.\n\nFor fetching many families at once, batch via `POST /v1/jobs/family`. The parent's counters may not include\nbulk-retry jobs spawned after the initial run -- aggregate across `children` for an accurate per-run summary.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id. Typically a parent flow job id, but any job id is accepted.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Job family (parent with inlined children).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobWithChildren"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Cancel a job

> Requests cancellation of a running or queued job. The job's \`status\` transitions to \`canceling\` and, once the\
> platform has stopped in-flight work, to \`canceled\`. This is \*\*not\*\* synchronous — the response returns the\
> updated job record with \`status: "canceling"\`; consumers should poll (e.g. \`GET /v1/jobs/{\_id}\`) to observe\
> the final \`canceled\` state.\
> \
> Only jobs that are still in progress (\`queued\`, \`running\`, \`retrying\`) can be canceled. Canceling a job\
> that is already terminal returns an error.\
> \
> Cancel at the flow-run (parent) level rather than individual export/import children -- child cancellations\
> can leave the parent in an inconsistent state.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"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/jobs/{_id}/cancel":{"put":{"operationId":"cancelJob","tags":["Jobs"],"summary":"Cancel a job","description":"Requests cancellation of a running or queued job. The job's `status` transitions to `canceling` and, once the\nplatform has stopped in-flight work, to `canceled`. This is **not** synchronous — the response returns the\nupdated job record with `status: \"canceling\"`; consumers should poll (e.g. `GET /v1/jobs/{_id}`) to observe\nthe final `canceled` state.\n\nOnly jobs that are still in progress (`queued`, `running`, `retrying`) can be canceled. Canceling a job\nthat is already terminal returns an error.\n\nCancel at the flow-run (parent) level rather than individual export/import children -- child cancellations\ncan leave the parent in an inconsistent state.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id to cancel.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Updated job record with `status: \"canceling\"`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"description":"The job is already in a terminal state and cannot be canceled.\nError code `job_already_ended`; the message names the job's current\nterminal state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get signed URL(s) to download job files

> Returns short-lived S3 pre-signed URLs for downloading files produced by the job (e.g. the rows exported to\
> a CSV, an error-record dump, or a page-processor artifact). The URLs are typically valid for \~15 minutes.\
> \
> If \`fileIds\` is omitted in the request body, all of the job's current file artifacts are returned. If\
> provided, only the matching files are included.\
> \
> Inspect the job's \`files\[]\` array first (via \`GET /v1/jobs/{\_id}\`) to discover available file IDs. Jobs\
> with no files (common for \`import\` child jobs or jobs past \`purgeAt\`) return \`204 No Content\`. File ids\
> are registered per job: if none of the requested \`fileIds\` are registered to this job (e.g. the file id\
> belongs to a different job's run), the endpoint also returns \`204 No Content\` with an empty body rather\
> than an error. The URLs expire after approximately 15 minutes -- fetch immediately, do not persist.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"JobFilesSignedUrlRequest":{"type":"object","description":"Request body for `POST /v1/jobs/{_id}/files/signedURL`.\nProvide `fileIds` to request signed URLs for specific files.\n","properties":{"fileIds":{"type":"array","description":"Optional list of job file ids to download.","items":{"type":"string"}}}},"JobFilesSignedUrlResponse":{"type":"object","description":"Signed URL response for downloading job files.","properties":{"signedURL":{"type":["string","null"],"description":"A single signed URL. Requests that pass `fileIds` return the `signedURLs` array instead, even for\na single file — check both fields."},"signedURLs":{"type":"array","description":"Signed URLs for the returned files, one per file. Returned as an array even when a single file is\nrequested via `fileIds`.","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/jobs/{_id}/files/signedURL":{"post":{"operationId":"getJobFilesSignedUrl","tags":["Jobs"],"summary":"Get signed URL(s) to download job files","description":"Returns short-lived S3 pre-signed URLs for downloading files produced by the job (e.g. the rows exported to\na CSV, an error-record dump, or a page-processor artifact). The URLs are typically valid for ~15 minutes.\n\nIf `fileIds` is omitted in the request body, all of the job's current file artifacts are returned. If\nprovided, only the matching files are included.\n\nInspect the job's `files[]` array first (via `GET /v1/jobs/{_id}`) to discover available file IDs. Jobs\nwith no files (common for `import` child jobs or jobs past `purgeAt`) return `204 No Content`. File ids\nare registered per job: if none of the requested `fileIds` are registered to this job (e.g. the file id\nbelongs to a different job's run), the endpoint also returns `204 No Content` with an empty body rather\nthan an error. The URLs expire after approximately 15 minutes -- fetch immediately, do not persist.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id whose files should be downloaded.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobFilesSignedUrlRequest"}}}},"responses":{"201":{"description":"One or more signed URLs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobFilesSignedUrlResponse"}}}},"204":{"description":"Job has no downloadable files, or none of the requested `fileIds` are registered to this job; the\nresponse body is empty."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Purge a job's stored files

> Deletes \*\*all\*\* file artifacts associated with the job (exported rows, error-record dumps, page-processor\
> artifacts, etc.) from underlying storage. After a successful call, \`GET /v1/jobs/{\_id}\` will show an empty\
> \`files\[]\` array and \`POST /v1/jobs/{\_id}/files/signedURL\` will return \`204 No Content\`.\
> \
> The job record itself is retained -- only the files are purged. This is irreversible. The platform also\
> purges files automatically at \`purgeAt\` / \`clickhousePurgeAt\`; manual purge is only needed for\
> storage-quota management or compliance workflows.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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/jobs/{_id}/files":{"delete":{"operationId":"purgeJobFiles","tags":["Jobs"],"summary":"Purge a job's stored files","description":"Deletes **all** file artifacts associated with the job (exported rows, error-record dumps, page-processor\nartifacts, etc.) from underlying storage. After a successful call, `GET /v1/jobs/{_id}` will show an empty\n`files[]` array and `POST /v1/jobs/{_id}/files/signedURL` will return `204 No Content`.\n\nThe job record itself is retained -- only the files are purged. This is irreversible. The platform also\npurges files automatically at `purgeAt` / `clickhousePurgeAt`; manual purge is only needed for\nstorage-quota management or compliance workflows.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id whose files should be purged.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Files purged successfully."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get a signed URL for job diagnostics

> Returns a short-lived S3 pre-signed URL pointing to a diagnostic archive (\`.zip\`) for the given job. The\
> archive contains server-side traces/logs that Celigo support uses to debug execution failures.\
> \
> The URL is typically valid for \~15 minutes (enforced by S3). Consumers should fetch the archive immediately\
> rather than storing the URL.\
> \
> This is distinct from flow execution logs -- use \`GET /v1/flows/{\_id}/jobs/{\_jobId}/logs\` for step-level\
> execution logs. Jobs with no diagnostics (very recent, or past \`purgeAt\`) return 204.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"JobDiagnosticsResponse":{"allOf":[{"$ref":"#/components/schemas/JobFilesSignedUrlResponse"},{"type":"object","description":"Signed URL response for downloading diagnostics for a job."}]},"JobFilesSignedUrlResponse":{"type":"object","description":"Signed URL response for downloading job files.","properties":{"signedURL":{"type":["string","null"],"description":"A single signed URL. Requests that pass `fileIds` return the `signedURLs` array instead, even for\na single file — check both fields."},"signedURLs":{"type":"array","description":"Signed URLs for the returned files, one per file. Returned as an array even when a single file is\nrequested via `fileIds`.","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/jobs/{_id}/diagnostics":{"get":{"operationId":"getJobDiagnostics","tags":["Jobs"],"summary":"Get a signed URL for job diagnostics","description":"Returns a short-lived S3 pre-signed URL pointing to a diagnostic archive (`.zip`) for the given job. The\narchive contains server-side traces/logs that Celigo support uses to debug execution failures.\n\nThe URL is typically valid for ~15 minutes (enforced by S3). Consumers should fetch the archive immediately\nrather than storing the URL.\n\nThis is distinct from flow execution logs -- use `GET /v1/flows/{_id}/jobs/{_jobId}/logs` for step-level\nexecution logs. Jobs with no diagnostics (very recent, or past `purgeAt`) return 204.","parameters":[{"name":"_id","in":"path","required":true,"description":"Job id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Signed URL for the diagnostics archive.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobDiagnosticsResponse"}}}},"204":{"description":"No diagnostics available for this job (archive may be absent or purged)."},"400":{"description":"The job does not support diagnostics downloads (`invalid_request`) —\ndiagnostics can only be downloaded for jobs with an associated\ndiagnostics archive.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get the most recent job(s) for a flow

> Returns the most recent job record(s) for the given flow. Typically one entry (the latest flow run), though\
> the platform may include related retry jobs depending on account configuration. For a richer parent+children\
> view, feed the returned \`\_id\` into \`GET /v1/jobs/{\_id}/family\`.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"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":{"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":{"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/latest":{"get":{"operationId":"getLatestFlowJobs","tags":["Jobs"],"summary":"Get the most recent job(s) for a flow","description":"Returns the most recent job record(s) for the given flow. Typically one entry (the latest flow run), though\nthe platform may include related retry jobs depending on account configuration. For a richer parent+children\nview, feed the returned `_id` into `GET /v1/jobs/{_id}/family`.","parameters":[{"name":"_id","in":"path","required":true,"description":"Flow id.","schema":{"type":"string","format":"objectId"}},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"Most recent job(s) for the flow. May be a single-element array.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}}},"204":{"description":"The flow has no recorded runs."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get the most recent job(s) for an integration

> Returns the most recent job record(s) across all flows in the given integration. Useful for a top-level\
> status check on an integration. The result is not filtered by status -- inspect each entry's \`status\` to\
> distinguish success from failure.

```json
{"openapi":"3.2.0","info":{"title":"Jobs","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Jobs are read-only records of flow, export, and import executions, created by the\nplatform whenever a run occurs. A parent flow job aggregates the run's counters while\nchild export/import jobs carry per-step counts, errors, and artifacts. Use these\nendpoints to monitor running jobs, inspect job families, download result files, and\ncancel or purge runs.\n\n## Job schema\n\n{% openapi-schemas spec=\"job\" schemas=\"Job\" 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":{"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":{"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/integrations/{_id}/jobs/latest":{"get":{"operationId":"getLatestIntegrationJobs","tags":["Jobs"],"summary":"Get the most recent job(s) for an integration","description":"Returns the most recent job record(s) across all flows in the given integration. Useful for a top-level\nstatus check on an integration. The result is not filtered by status -- inspect each entry's `status` to\ndistinguish success from failure.","parameters":[{"name":"_id","in":"path","required":true,"description":"Integration id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Most recent job(s) for the integration.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}}},"204":{"description":"The integration has no recorded runs."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```
