> 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/api-management/apis.md).

# APIs

APIs expose integration logic as HTTP endpoints that external systems can invoke.

Two modes:

* **Builder** — visual configuration with request/response mapping, routing, and transformations
* **Script** — custom JavaScript handler function for full control

Each API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`

### API schema

## The API object

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"components":{"schemas":{"API":{"required":["_id","name","createdAt","lastModified"],"description":"API resource. Shape varies by mode: builder-mode APIs carry `type`, `version`,\n`disabled`, and `builder`; script-mode APIs additionally carry `script` plus\ntop-level `_scriptId` / `function` copies. Legacy script APIs (pre-builder era)\nomit `type`, `version`, `disabled`, and `builder` entirely.","allOf":[{"$ref":"#/components/schemas/APIBase"},{"type":"object","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the API."},"_scriptId":{"type":"string","format":"objectId","readOnly":true,"description":"Top-level copy of `script._scriptId`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"function":{"type":"string","readOnly":true,"description":"Top-level copy of `script.function`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was last modified."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this API was created from. Present only on template-installed APIs."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft API auto-deletes. Server-computed when `draft` is set at\ncreation."},"apim":{"$ref":"#/components/schemas/Apim"}}}]},"APIBase":{"type":"object","description":"Writable fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this API belongs to. **Builder mode only** — a script-mode\nAPI is always account-level and the server silently drops this field.\nSend `null` (or omit) to keep the API account-level; on reads the field\nis omitted when unset, never `null`."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"One of the owning integration's `apiGroupings`, subdividing its APIs.\nRequires `_integrationId` in the same write — sent without it, the server\nsilently drops both — so builder mode only. `PUT /v1/apis/updateApiGrouping`\nregroups many APIs at once; this field carries the same value on a single\nAPI. On reads the field is omitted when unset, never `null`."},"description":{"type":"string","description":"Optional description of the API's purpose."},"type":{"type":"string","enum":["builder","script"],"default":"script","description":"API mode. Cannot be changed after creation. Defaults to `script` when\nomitted on create; legacy script APIs created before builder mode may\nomit it on reads as well."},"version":{"type":"string","default":"v1","pattern":"^[a-zA-Z0-9\\-_\\.]+$","description":"Version segment of the public URL (`/apis/{version}{relativeURI}`)."},"disabled":{"type":"boolean","default":false,"description":"When true, the API rejects all incoming requests."},"timeoutPeriod":{"type":"integer","minimum":0,"maximum":120,"description":"Request-timeout override in seconds (1–120). `0` is a sentinel meaning \"use the\n120-second default\" — the server rewrites it on write, so a stored value is never 0."},"logging":{"type":"object","description":"Execution-logging settings for the API. Builder-mode APIs are\ninitialized to `{\"mode\": \"basic\"}` at creation (when the account\nlicense has logging enabled), so the field is present on responses\nfrom the start.\n\nPOST and PUT bodies cannot set or change this field — the server\nignores it silently (the write succeeds and the stored value is\nuntouched). `PATCH /v1/apis/{_id}` with the `/logging/mode` and\n`/logging/debugUntil` paths is the only way to change it.","properties":{"mode":{"type":"string","enum":["basic","standard","detailed","accountLevel","noLogging"],"description":"Which logging level applies to requests handled by this API. Every\nmode that logs records the step list that\n`GET /v1/apis/{_id}/requests/{executionId}` returns, `basic` included;\nthe level decides how much per-record payload the log-data query can\nreturn. Payload-capturing modes (`standard`, `detailed`) require payload\nstorage to be enabled for the account — without it, changing the\nmode fails with `422` (code `payload_storage_required`)."},"debugUntil":{"type":"string","format":"date-time","description":"While this timestamp is in the future, requests are captured in\nfull debug mode regardless of `mode`. Clears itself once the\nwindow passes. Setting it requires payload storage to be enabled\nfor the account."}}},"traceKeyTemplate":{"type":"string","maxLength":1024,"description":"Handlebars template that computes each request's trace key from the\nrequest payload, used to correlate run-history entries with source\nrecords. Absent from responses until set."},"pagination":{"type":"object","description":"Cursor pagination for builder-mode APIs. The first lookup (export\nstep) in `builder.routers` is the volume driver: when pagination is\nenabled, each call to the public endpoint returns one source page of\nthat lookup instead of draining it. The mapped response body keeps its\nown keys at the root and gains one reserved `pagination` object,\n`{\"has_more\": boolean, \"next_cursor\": string}` — no `data` wrapper.\n`next_cursor` is present only while `has_more` is true, and a page\nthat maps to no records is just `{\"pagination\": {\"has_more\": false}}`.\nA root-level `pagination` mapping in the success response is\noverwritten by the platform object at runtime.\n\nCallers fetch the next page by resending the request unchanged with\nthe cursor in the `Celigo-Next-Cursor` request header — for every\nHTTP method; a `next_cursor` field in the request body is ordinary\npayload, not a cursor. Resending a cursor returns the same page again.\nCursor faults fail the invocation with `400`:\n`invalid_cursor_format`, `cursor_signature_invalid` (the cursor was\naltered), `cursor_version_unsupported`, `cursor_api_mismatch` (the\ncursor was issued by a different API), `cursor_filter_mismatch` (the\npath, query, or body differs from the request that issued the cursor),\nor `cursor_not_supported_for_api` (a cursor sent to an API whose\npagination is off). Cursors expire and are then rejected with `410\ncursor_expired`; a response hook that turns the mapped body into a\nnon-object fails with `422 api_pagination_response_not_object`.\n\nSaving the volume-driver export — even with no changes — invalidates\nevery cursor issued so far: the next call with one returns `200` with\nan empty final page, `{\"pagination\": {\"has_more\": false}}`, as if the\nsource were exhausted; restart from the first page without a cursor.\nSaving the API document itself leaves issued cursors valid.\nA success response whose `statusCode` is `204` returns no body, so the\n`pagination` object and cursor are lost with it — a paginated API\nneeds a body-bearing success status.\n\nAbsent from responses until set. A PUT that omits `pagination` keeps\nthe stored value; send `{\"enabled\": null}` to clear it (the field is\nthen absent again).","properties":{"enabled":{"type":"boolean","description":"When true, invocations return one volume-driver page per request\nplus the reserved `pagination` object, and accept the\n`Celigo-Next-Cursor` header. Saving `true` requires a builder-mode\nAPI whose first lookup is an HTTP, Salesforce, or NetSuite export\nwith source paging configured; otherwise the write fails with\n`422` `api_pagination_no_volume_driver` (no lookup at all),\n`api_pagination_adapter_not_supported` (any other adaptor), or\n`api_pagination_source_not_paged` (lookup without paging). The\nsame check repeats on every later save of the API and at every\ninvocation while the stored value is true: if the volume driver\nloses its paging afterwards (the export save itself succeeds),\nevery call fails with `400 api_pagination_source_not_paged` and\nevery PUT or PATCH of the API — including one that omits\n`pagination` — is refused with the `422` until paging is restored\nor this flag is set to false. When false, a `Celigo-Next-Cursor`\nheader is rejected with `400 cursor_not_supported_for_api`."}}},"script":{"$ref":"#/components/schemas/Script"},"builder":{"$ref":"#/components/schemas/Builder"},"shipworks":{"$ref":"#/components/schemas/Shipworks"},"draft":{"type":"boolean","description":"When true, this API is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."}}},"Script":{"type":"object","description":"Script-mode configuration. Callers reach the API at `/v1/apis/{_id}/request`, and the\nreferenced function is called with one `options` object: `method`, `headers` (the\nrequest's headers, without `Authorization`), `queryString` (the parsed query string),\n`body`, and `rawBody` (the body as received, a string). On a GET, `body` is absent and\n`rawBody` is empty. It returns `{statusCode, headers, body}`: `headers` is optional,\nand `body` may be any JSON value, an array included.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource containing the handler function."},"function":{"type":"string","description":"Name of the function to invoke within the script."}},"required":["_scriptId","function"]},"Builder":{"type":"object","description":"Builder-mode configuration defining request structure, routing, and response mapping.","properties":{"request":{"$ref":"#/components/schemas/ApiRequest"},"routers":{"type":"array","description":"Optional routers for conditional processing before the response stage.","items":{"$ref":"#/components/schemas/Router"}},"responseRouter":{"$ref":"#/components/schemas/ResponseRouter"},"responses":{"type":"array","description":"Response configurations. Must include exactly one `success` and one `fail`\nresponse; additional `custom` responses are optional. Order matters: the response\nrouter returns the first response whose `inputFilter` matches, and a response without\none matches every request.","items":{"$ref":"#/components/schemas/ApiResponse"}}}},"ApiRequest":{"type":"object","description":"Request configuration for a builder-mode API endpoint.","properties":{"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9:_*\\/\\-\\.]*$","description":"URI path relative to the version. Callers reach the API at\n`https://api.integrator.io/apis/{version}{relativeURI}` (on the account's regional\nhost outside the US), with the account's API token. Use colon notation for path\nparams: `/customers/:id`."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method for the API endpoint."},"headers":{"type":"array","description":"Expected request headers.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"description":{"type":"string","maxLength":10240,"description":"Description of the header's purpose"}}}},"pathParams":{"type":"array","description":"Path parameters defined in the `relativeURI`.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"description":"Parameter name (without the colon prefix)"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"queryParams":{"type":"array","description":"Expected query string parameters.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_\\-:\\/]*$","description":"Query parameter name"},"dataType":{"type":"string","enum":["string","number","boolean"],"description":"Expected data type of the parameter"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the expected request body structure. Every\nobject-typed schema node must declare at least one property for the\nAPI Builder to render it; omit this field when the endpoint has no\nbody contract.","additionalProperties":true},"mockRequest":{"type":"object","description":"Sample request saved with the API for testing. `POST /v1/apis/{_id}/test/run` doesn't\nread it; send it as that call's `mockRequest`. A test run still makes outside calls: a\nlookup with no saved `mockOutput` calls its source live, and the run saves that response\nas the lookup's `mockOutput`, which later test runs answer from.","properties":{"body":{"type":"object","description":"Sample request body"},"headers":{"type":"object","description":"Sample headers"},"pathParams":{"type":"object","description":"Sample path parameters"},"queryParams":{"type":"object","description":"Sample query parameters"}},"additionalProperties":false},"transform":{"type":"object","description":"Optional transformation applied to the incoming request before processing. The\nexpression form (`type: \"expression\"` with Transformation 2.0 rules in `expression`)\nsaves and runs. In a test run its rules see only the request body, not `pathParams`,\n`queryParams` or headers.","properties":{"type":{"type":"string","description":"Selects the transform form; `expression` runs the rules in `expression`."},"expression":{"type":"object","description":"Transformation 2.0 rules applied to the request body.","properties":{"version":{"type":"string","description":"Rule format; `\"2\"` selects the rules in `rulesTwoDotZero`."},"rulesTwoDotZero":{"type":"object","description":"The rules applied to the request body.","properties":{"mode":{"type":"string","enum":["create","modify"],"description":"How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones."},"mappings":{"type":"array","description":"Mapper 2.0 rows that write fields onto the record.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}}}}}}},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a script for custom transformation logic."},"function":{"type":"string","description":"Function name in the script to execute."}}}},"required":["relativeURI","method"]},"items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}},"Router":{"type":"object","description":"Conditional routing within a builder-mode API. Unlike flows, APIs only\nsupport `first_matching_branch` routing.\n\nA router comes in two shapes, told apart by whether `routeRecordsTo` and\n`routeRecordsUsing` are set: a **branching router** sets both and has two or\nmore branches, each taking the requests its `inputFilter` (or the router's\n`script`) matches — the node you see in the API builder; a **pass-through\nrouter** sets neither and has exactly one branch that every request goes\nstraight through — not drawn, it holds the steps before the first branching\nrouter and merges branches back into shared steps (branches rejoin only by\npointing `nextRouterId` at the same router).","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the API. Use at most 36 letters, digits,\nunderscores and hyphens: a longer id fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the router\nid.\"), as on flow routers."},"name":{"type":"string","description":"Display name."},"routeRecordsTo":{"type":"string","enum":["first_matching_branch"],"description":"Routing strategy; APIs only support `first_matching_branch`. Set together with\n`routeRecordsUsing` on a branching router; leave both unset on a one-branch\npass-through router."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"How a branching router decides which branch a request matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router."},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the branch name."}}},"branches":{"type":"array","description":"Processing branches, evaluated in order.","items":{"type":"object","properties":{"name":{"type":"string","description":"Branch name"},"inputFilter":{"type":"object","description":"Filter criteria for branch selection. Send `version` and `rules` directly on\n`inputFilter` — not inside the `{type: \"expression\", expression: {...}}` wrapper\nthat export and import filters use. A wrapped filter is saved without an error,\nbut the branch is stored with no `inputFilter` and takes every request.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"nextRouterId":{"type":"string","description":"Next router to chain to, or \"apiRouter\" for the response router. Every branch needs\none: a branch without it is saved, but every test run of the API is then refused\nwith 400 \"One or more branches are not merged back. Review the setup to ensure all\nbranches converge.\", whichever branch the request takes. An id that names no router\nfails the save with 422 \"Invalid nextRouterId is defined on the branch. Please\ncorrect the branch configuration.\""},"pageProcessors":{"type":"array","description":"Processing steps to execute in this branch. An export is a step at most once in an\nAPI: using it again, on another branch or in the same one, fails the save with 422\n\"The export <id> is already included as a lookup in your API and cannot be added\nagain.\"","items":{"type":"object","properties":{"type":{"type":"string","enum":["export","import"],"description":"Type of processor"},"_exportId":{"type":"string","format":"objectId","description":"Export resource reference (when type=\"export\")."},"_importId":{"type":"string","format":"objectId","description":"Import resource reference (when type=\"import\")."},"hooks":{"type":"object","description":"Custom scripts for processing"},"proceedOnFailure":{"type":"boolean","description":"When true, the next step still runs after this step fails, and the request\ncan still end in the `success` response (`context.success` stays true).\nWhen false, a failure stops the branch and the API returns its `fail`\nresponse."}}}}}}}},"required":["branches"]},"ResponseRouter":{"type":"object","description":"Final routing step that selects which response configuration to return.\nMust have `id: \"apiRouter\"`.","properties":{"id":{"type":"string","enum":["apiRouter"],"description":"Must be `\"apiRouter\"`."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Method used to determine which response to use."},"script":{"type":"object","description":"Script configuration when `routeRecordsUsing` is `\"script\"`.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the response id."}}}}},"ApiResponse":{"type":"object","description":"Response configuration in a builder-mode API. Each API requires exactly one\n`success` and one `fail` response; additional `custom` responses are optional.","properties":{"id":{"type":"string","description":"Unique identifier for this response, referenced by the response router."},"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description of when this response is used."},"type":{"type":"string","enum":["success","fail","custom"],"description":"Response type. `success` isn't a fallback checked after the `custom` responses: list\n`custom` responses before it (see `inputFilter`)."},"statusCode":{"type":"integer","minimum":100,"maximum":599,"description":"HTTP status code to return."},"headers":{"type":"array","description":"Response headers to include.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"value":{"type":"string","maxLength":256,"description":"Header value (can include handlebars templates)"},"description":{"type":"string","maxLength":10240,"description":"Description of the header"}}}},"inputFilter":{"type":"object","description":"Filter criteria for response selection by the response router, which returns the first\nresponse in `responses` whose filter matches. A response without an `inputFilter` matches\nevery request, so a `success` listed first answers requests a later `custom` filter\nmatches; the typed `context.success` filter doesn't prevent that, because\n`context.success` is true whenever no step failed, including when a lookup found nothing.\nA step that fails with `proceedOnFailure` off selects the `fail` response.\n\nSend `version` and `rules` directly on `inputFilter`, not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import filters use. A\nwrapped filter is saved without an error, but the response is stored with no\n`inputFilter`, so it matches every request that reaches it.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the response body structure. Every object-typed\nschema node must declare at least one property for the API Builder to\nrender it; omit this field when the response body has no defined shape.","additionalProperties":true},"mockInput":{"type":["object","string"],"maxLength":0,"description":"Mock data for testing this response, in the integrator.io canonical\nrecord-page format: `{\"page_of_records\": [{\"record\": {...}}, ...]}`.\nThe server rejects any other object shape and any non-empty string\nwith a 422; the empty string `\"\"` (a UI draft artifact) is accepted\nand stored verbatim.","required":["page_of_records"],"properties":{"page_of_records":{"type":"array","description":"Pages of mock records fed to this response's mappings.","items":{"type":"object","required":["record"],"properties":{"record":{"type":"object","description":"One mock input record (freeform payload)."},"success":{"type":"boolean","description":"When true, the mock record follows the success path."},"testMode":{"type":"boolean","description":"When true, the mock record is treated as a test-mode record."}}}}},"additionalProperties":true},"mappings":{"type":"array","description":"Mapper 2.0 rows that build the response body from the record the steps produced,\nunder the same rules as the shared Mapper 2.0 schema an import's `mappings` use.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}}},"lookups":{"type":"array","description":"Static key-value lookup tables for value transformation.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the lookup"},"map":{"type":"object","description":"Key-value mapping object"},"default":{"type":"string","description":"Default value if key not found"},"allowFailures":{"type":"boolean","description":"When true, processing continues even if this lookup fails."}}}},"hooks":{"type":"object","description":"Custom scripts to run during response processing.","properties":{"preMap":{"type":"object","description":"Script to run before applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}},"postMap":{"type":"object","description":"Script to run after applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}}}}}},"items-2":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}},"Shipworks":{"type":"object","description":"ShipWorks shipping-management credentials. Legacy feature.","properties":{"username":{"type":"string","description":"ShipWorks username."},"password":{"type":"string","description":"ShipWorks password. Masked as `\"******\"` in GET responses."}},"required":["username","password"]},"Apim":{"type":"array","readOnly":true,"description":"Publication status of this API in external API management systems.","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier assigned by the external API management system (a UUID, not a Celigo API _id)."},"flowId":{"type":"string","description":"Associated flow identifier in the external API management system (a UUID, not a Celigo flow _id). Empty when no flow is associated."},"status":{"type":"string","enum":["oaspending","published"],"description":"Publication status."},"definitionVersion":{"type":"string","enum":["v4"],"description":"API definition format version."}}}}}}}
```

## List APIs

> Returns the APIs configured in the account, cursor-paginated via the \`Link\` header when\
> \`limit\` is set. Legacy script-mode APIs (created before the builder/script distinction) may\
> omit \`type\`, \`version\`, and \`disabled\`. A 204 response means nothing matched.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"parameters":{"After":{"name":"after","in":"query","required":false,"description":"Opaque cursor for forward pagination. Pass the value from the `Link`\nresponse header (`rel=\"next\"`) to fetch the next page.","schema":{"type":"string"}},"Include":{"name":"include","in":"query","required":false,"description":"Comma-separated list of fields to project into each returned record.\nTriggers summary projection: the response contains a minimal identity\nset (`_id`, `name`, plus resource-specific fields) with the requested\nfields added on top. Supports dot notation for nested fields.\nMutually exclusive with `exclude`.","schema":{"type":"string"}},"Exclude":{"name":"exclude","in":"query","required":false,"description":"Comma-separated list of fields to strip from the default response.\nUnlike `include`, does not trigger summary projection — returns the\nfull record with the named fields removed. Protected identity fields\n(e.g. `name`) cannot be stripped. Mutually exclusive with `include`.","schema":{"type":"string"}}},"schemas":{"API":{"required":["_id","name","createdAt","lastModified"],"description":"API resource. Shape varies by mode: builder-mode APIs carry `type`, `version`,\n`disabled`, and `builder`; script-mode APIs additionally carry `script` plus\ntop-level `_scriptId` / `function` copies. Legacy script APIs (pre-builder era)\nomit `type`, `version`, `disabled`, and `builder` entirely.","allOf":[{"$ref":"#/components/schemas/APIBase"},{"type":"object","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the API."},"_scriptId":{"type":"string","format":"objectId","readOnly":true,"description":"Top-level copy of `script._scriptId`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"function":{"type":"string","readOnly":true,"description":"Top-level copy of `script.function`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was last modified."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this API was created from. Present only on template-installed APIs."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft API auto-deletes. Server-computed when `draft` is set at\ncreation."},"apim":{"$ref":"#/components/schemas/Apim"}}}]},"APIBase":{"type":"object","description":"Writable fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this API belongs to. **Builder mode only** — a script-mode\nAPI is always account-level and the server silently drops this field.\nSend `null` (or omit) to keep the API account-level; on reads the field\nis omitted when unset, never `null`."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"One of the owning integration's `apiGroupings`, subdividing its APIs.\nRequires `_integrationId` in the same write — sent without it, the server\nsilently drops both — so builder mode only. `PUT /v1/apis/updateApiGrouping`\nregroups many APIs at once; this field carries the same value on a single\nAPI. On reads the field is omitted when unset, never `null`."},"description":{"type":"string","description":"Optional description of the API's purpose."},"type":{"type":"string","enum":["builder","script"],"default":"script","description":"API mode. Cannot be changed after creation. Defaults to `script` when\nomitted on create; legacy script APIs created before builder mode may\nomit it on reads as well."},"version":{"type":"string","default":"v1","pattern":"^[a-zA-Z0-9\\-_\\.]+$","description":"Version segment of the public URL (`/apis/{version}{relativeURI}`)."},"disabled":{"type":"boolean","default":false,"description":"When true, the API rejects all incoming requests."},"timeoutPeriod":{"type":"integer","minimum":0,"maximum":120,"description":"Request-timeout override in seconds (1–120). `0` is a sentinel meaning \"use the\n120-second default\" — the server rewrites it on write, so a stored value is never 0."},"logging":{"type":"object","description":"Execution-logging settings for the API. Builder-mode APIs are\ninitialized to `{\"mode\": \"basic\"}` at creation (when the account\nlicense has logging enabled), so the field is present on responses\nfrom the start.\n\nPOST and PUT bodies cannot set or change this field — the server\nignores it silently (the write succeeds and the stored value is\nuntouched). `PATCH /v1/apis/{_id}` with the `/logging/mode` and\n`/logging/debugUntil` paths is the only way to change it.","properties":{"mode":{"type":"string","enum":["basic","standard","detailed","accountLevel","noLogging"],"description":"Which logging level applies to requests handled by this API. Every\nmode that logs records the step list that\n`GET /v1/apis/{_id}/requests/{executionId}` returns, `basic` included;\nthe level decides how much per-record payload the log-data query can\nreturn. Payload-capturing modes (`standard`, `detailed`) require payload\nstorage to be enabled for the account — without it, changing the\nmode fails with `422` (code `payload_storage_required`)."},"debugUntil":{"type":"string","format":"date-time","description":"While this timestamp is in the future, requests are captured in\nfull debug mode regardless of `mode`. Clears itself once the\nwindow passes. Setting it requires payload storage to be enabled\nfor the account."}}},"traceKeyTemplate":{"type":"string","maxLength":1024,"description":"Handlebars template that computes each request's trace key from the\nrequest payload, used to correlate run-history entries with source\nrecords. Absent from responses until set."},"pagination":{"type":"object","description":"Cursor pagination for builder-mode APIs. The first lookup (export\nstep) in `builder.routers` is the volume driver: when pagination is\nenabled, each call to the public endpoint returns one source page of\nthat lookup instead of draining it. The mapped response body keeps its\nown keys at the root and gains one reserved `pagination` object,\n`{\"has_more\": boolean, \"next_cursor\": string}` — no `data` wrapper.\n`next_cursor` is present only while `has_more` is true, and a page\nthat maps to no records is just `{\"pagination\": {\"has_more\": false}}`.\nA root-level `pagination` mapping in the success response is\noverwritten by the platform object at runtime.\n\nCallers fetch the next page by resending the request unchanged with\nthe cursor in the `Celigo-Next-Cursor` request header — for every\nHTTP method; a `next_cursor` field in the request body is ordinary\npayload, not a cursor. Resending a cursor returns the same page again.\nCursor faults fail the invocation with `400`:\n`invalid_cursor_format`, `cursor_signature_invalid` (the cursor was\naltered), `cursor_version_unsupported`, `cursor_api_mismatch` (the\ncursor was issued by a different API), `cursor_filter_mismatch` (the\npath, query, or body differs from the request that issued the cursor),\nor `cursor_not_supported_for_api` (a cursor sent to an API whose\npagination is off). Cursors expire and are then rejected with `410\ncursor_expired`; a response hook that turns the mapped body into a\nnon-object fails with `422 api_pagination_response_not_object`.\n\nSaving the volume-driver export — even with no changes — invalidates\nevery cursor issued so far: the next call with one returns `200` with\nan empty final page, `{\"pagination\": {\"has_more\": false}}`, as if the\nsource were exhausted; restart from the first page without a cursor.\nSaving the API document itself leaves issued cursors valid.\nA success response whose `statusCode` is `204` returns no body, so the\n`pagination` object and cursor are lost with it — a paginated API\nneeds a body-bearing success status.\n\nAbsent from responses until set. A PUT that omits `pagination` keeps\nthe stored value; send `{\"enabled\": null}` to clear it (the field is\nthen absent again).","properties":{"enabled":{"type":"boolean","description":"When true, invocations return one volume-driver page per request\nplus the reserved `pagination` object, and accept the\n`Celigo-Next-Cursor` header. Saving `true` requires a builder-mode\nAPI whose first lookup is an HTTP, Salesforce, or NetSuite export\nwith source paging configured; otherwise the write fails with\n`422` `api_pagination_no_volume_driver` (no lookup at all),\n`api_pagination_adapter_not_supported` (any other adaptor), or\n`api_pagination_source_not_paged` (lookup without paging). The\nsame check repeats on every later save of the API and at every\ninvocation while the stored value is true: if the volume driver\nloses its paging afterwards (the export save itself succeeds),\nevery call fails with `400 api_pagination_source_not_paged` and\nevery PUT or PATCH of the API — including one that omits\n`pagination` — is refused with the `422` until paging is restored\nor this flag is set to false. When false, a `Celigo-Next-Cursor`\nheader is rejected with `400 cursor_not_supported_for_api`."}}},"script":{"$ref":"#/components/schemas/Script"},"builder":{"$ref":"#/components/schemas/Builder"},"shipworks":{"$ref":"#/components/schemas/Shipworks"},"draft":{"type":"boolean","description":"When true, this API is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."}}},"Script":{"type":"object","description":"Script-mode configuration. Callers reach the API at `/v1/apis/{_id}/request`, and the\nreferenced function is called with one `options` object: `method`, `headers` (the\nrequest's headers, without `Authorization`), `queryString` (the parsed query string),\n`body`, and `rawBody` (the body as received, a string). On a GET, `body` is absent and\n`rawBody` is empty. It returns `{statusCode, headers, body}`: `headers` is optional,\nand `body` may be any JSON value, an array included.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource containing the handler function."},"function":{"type":"string","description":"Name of the function to invoke within the script."}},"required":["_scriptId","function"]},"Builder":{"type":"object","description":"Builder-mode configuration defining request structure, routing, and response mapping.","properties":{"request":{"$ref":"#/components/schemas/ApiRequest"},"routers":{"type":"array","description":"Optional routers for conditional processing before the response stage.","items":{"$ref":"#/components/schemas/Router"}},"responseRouter":{"$ref":"#/components/schemas/ResponseRouter"},"responses":{"type":"array","description":"Response configurations. Must include exactly one `success` and one `fail`\nresponse; additional `custom` responses are optional. Order matters: the response\nrouter returns the first response whose `inputFilter` matches, and a response without\none matches every request.","items":{"$ref":"#/components/schemas/ApiResponse"}}}},"ApiRequest":{"type":"object","description":"Request configuration for a builder-mode API endpoint.","properties":{"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9:_*\\/\\-\\.]*$","description":"URI path relative to the version. Callers reach the API at\n`https://api.integrator.io/apis/{version}{relativeURI}` (on the account's regional\nhost outside the US), with the account's API token. Use colon notation for path\nparams: `/customers/:id`."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method for the API endpoint."},"headers":{"type":"array","description":"Expected request headers.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"description":{"type":"string","maxLength":10240,"description":"Description of the header's purpose"}}}},"pathParams":{"type":"array","description":"Path parameters defined in the `relativeURI`.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"description":"Parameter name (without the colon prefix)"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"queryParams":{"type":"array","description":"Expected query string parameters.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_\\-:\\/]*$","description":"Query parameter name"},"dataType":{"type":"string","enum":["string","number","boolean"],"description":"Expected data type of the parameter"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the expected request body structure. Every\nobject-typed schema node must declare at least one property for the\nAPI Builder to render it; omit this field when the endpoint has no\nbody contract.","additionalProperties":true},"mockRequest":{"type":"object","description":"Sample request saved with the API for testing. `POST /v1/apis/{_id}/test/run` doesn't\nread it; send it as that call's `mockRequest`. A test run still makes outside calls: a\nlookup with no saved `mockOutput` calls its source live, and the run saves that response\nas the lookup's `mockOutput`, which later test runs answer from.","properties":{"body":{"type":"object","description":"Sample request body"},"headers":{"type":"object","description":"Sample headers"},"pathParams":{"type":"object","description":"Sample path parameters"},"queryParams":{"type":"object","description":"Sample query parameters"}},"additionalProperties":false},"transform":{"type":"object","description":"Optional transformation applied to the incoming request before processing. The\nexpression form (`type: \"expression\"` with Transformation 2.0 rules in `expression`)\nsaves and runs. In a test run its rules see only the request body, not `pathParams`,\n`queryParams` or headers.","properties":{"type":{"type":"string","description":"Selects the transform form; `expression` runs the rules in `expression`."},"expression":{"type":"object","description":"Transformation 2.0 rules applied to the request body.","properties":{"version":{"type":"string","description":"Rule format; `\"2\"` selects the rules in `rulesTwoDotZero`."},"rulesTwoDotZero":{"type":"object","description":"The rules applied to the request body.","properties":{"mode":{"type":"string","enum":["create","modify"],"description":"How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones."},"mappings":{"type":"array","description":"Mapper 2.0 rows that write fields onto the record.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}}}}}}},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a script for custom transformation logic."},"function":{"type":"string","description":"Function name in the script to execute."}}}},"required":["relativeURI","method"]},"items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}},"Router":{"type":"object","description":"Conditional routing within a builder-mode API. Unlike flows, APIs only\nsupport `first_matching_branch` routing.\n\nA router comes in two shapes, told apart by whether `routeRecordsTo` and\n`routeRecordsUsing` are set: a **branching router** sets both and has two or\nmore branches, each taking the requests its `inputFilter` (or the router's\n`script`) matches — the node you see in the API builder; a **pass-through\nrouter** sets neither and has exactly one branch that every request goes\nstraight through — not drawn, it holds the steps before the first branching\nrouter and merges branches back into shared steps (branches rejoin only by\npointing `nextRouterId` at the same router).","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the API. Use at most 36 letters, digits,\nunderscores and hyphens: a longer id fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the router\nid.\"), as on flow routers."},"name":{"type":"string","description":"Display name."},"routeRecordsTo":{"type":"string","enum":["first_matching_branch"],"description":"Routing strategy; APIs only support `first_matching_branch`. Set together with\n`routeRecordsUsing` on a branching router; leave both unset on a one-branch\npass-through router."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"How a branching router decides which branch a request matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router."},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the branch name."}}},"branches":{"type":"array","description":"Processing branches, evaluated in order.","items":{"type":"object","properties":{"name":{"type":"string","description":"Branch name"},"inputFilter":{"type":"object","description":"Filter criteria for branch selection. Send `version` and `rules` directly on\n`inputFilter` — not inside the `{type: \"expression\", expression: {...}}` wrapper\nthat export and import filters use. A wrapped filter is saved without an error,\nbut the branch is stored with no `inputFilter` and takes every request.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"nextRouterId":{"type":"string","description":"Next router to chain to, or \"apiRouter\" for the response router. Every branch needs\none: a branch without it is saved, but every test run of the API is then refused\nwith 400 \"One or more branches are not merged back. Review the setup to ensure all\nbranches converge.\", whichever branch the request takes. An id that names no router\nfails the save with 422 \"Invalid nextRouterId is defined on the branch. Please\ncorrect the branch configuration.\""},"pageProcessors":{"type":"array","description":"Processing steps to execute in this branch. An export is a step at most once in an\nAPI: using it again, on another branch or in the same one, fails the save with 422\n\"The export <id> is already included as a lookup in your API and cannot be added\nagain.\"","items":{"type":"object","properties":{"type":{"type":"string","enum":["export","import"],"description":"Type of processor"},"_exportId":{"type":"string","format":"objectId","description":"Export resource reference (when type=\"export\")."},"_importId":{"type":"string","format":"objectId","description":"Import resource reference (when type=\"import\")."},"hooks":{"type":"object","description":"Custom scripts for processing"},"proceedOnFailure":{"type":"boolean","description":"When true, the next step still runs after this step fails, and the request\ncan still end in the `success` response (`context.success` stays true).\nWhen false, a failure stops the branch and the API returns its `fail`\nresponse."}}}}}}}},"required":["branches"]},"ResponseRouter":{"type":"object","description":"Final routing step that selects which response configuration to return.\nMust have `id: \"apiRouter\"`.","properties":{"id":{"type":"string","enum":["apiRouter"],"description":"Must be `\"apiRouter\"`."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Method used to determine which response to use."},"script":{"type":"object","description":"Script configuration when `routeRecordsUsing` is `\"script\"`.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the response id."}}}}},"ApiResponse":{"type":"object","description":"Response configuration in a builder-mode API. Each API requires exactly one\n`success` and one `fail` response; additional `custom` responses are optional.","properties":{"id":{"type":"string","description":"Unique identifier for this response, referenced by the response router."},"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description of when this response is used."},"type":{"type":"string","enum":["success","fail","custom"],"description":"Response type. `success` isn't a fallback checked after the `custom` responses: list\n`custom` responses before it (see `inputFilter`)."},"statusCode":{"type":"integer","minimum":100,"maximum":599,"description":"HTTP status code to return."},"headers":{"type":"array","description":"Response headers to include.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"value":{"type":"string","maxLength":256,"description":"Header value (can include handlebars templates)"},"description":{"type":"string","maxLength":10240,"description":"Description of the header"}}}},"inputFilter":{"type":"object","description":"Filter criteria for response selection by the response router, which returns the first\nresponse in `responses` whose filter matches. A response without an `inputFilter` matches\nevery request, so a `success` listed first answers requests a later `custom` filter\nmatches; the typed `context.success` filter doesn't prevent that, because\n`context.success` is true whenever no step failed, including when a lookup found nothing.\nA step that fails with `proceedOnFailure` off selects the `fail` response.\n\nSend `version` and `rules` directly on `inputFilter`, not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import filters use. A\nwrapped filter is saved without an error, but the response is stored with no\n`inputFilter`, so it matches every request that reaches it.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the response body structure. Every object-typed\nschema node must declare at least one property for the API Builder to\nrender it; omit this field when the response body has no defined shape.","additionalProperties":true},"mockInput":{"type":["object","string"],"maxLength":0,"description":"Mock data for testing this response, in the integrator.io canonical\nrecord-page format: `{\"page_of_records\": [{\"record\": {...}}, ...]}`.\nThe server rejects any other object shape and any non-empty string\nwith a 422; the empty string `\"\"` (a UI draft artifact) is accepted\nand stored verbatim.","required":["page_of_records"],"properties":{"page_of_records":{"type":"array","description":"Pages of mock records fed to this response's mappings.","items":{"type":"object","required":["record"],"properties":{"record":{"type":"object","description":"One mock input record (freeform payload)."},"success":{"type":"boolean","description":"When true, the mock record follows the success path."},"testMode":{"type":"boolean","description":"When true, the mock record is treated as a test-mode record."}}}}},"additionalProperties":true},"mappings":{"type":"array","description":"Mapper 2.0 rows that build the response body from the record the steps produced,\nunder the same rules as the shared Mapper 2.0 schema an import's `mappings` use.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}}},"lookups":{"type":"array","description":"Static key-value lookup tables for value transformation.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the lookup"},"map":{"type":"object","description":"Key-value mapping object"},"default":{"type":"string","description":"Default value if key not found"},"allowFailures":{"type":"boolean","description":"When true, processing continues even if this lookup fails."}}}},"hooks":{"type":"object","description":"Custom scripts to run during response processing.","properties":{"preMap":{"type":"object","description":"Script to run before applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}},"postMap":{"type":"object","description":"Script to run after applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}}}}}},"items-2":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}},"Shipworks":{"type":"object","description":"ShipWorks shipping-management credentials. Legacy feature.","properties":{"username":{"type":"string","description":"ShipWorks username."},"password":{"type":"string","description":"ShipWorks password. Masked as `\"******\"` in GET responses."}},"required":["username","password"]},"Apim":{"type":"array","readOnly":true,"description":"Publication status of this API in external API management systems.","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier assigned by the external API management system (a UUID, not a Celigo API _id)."},"flowId":{"type":"string","description":"Associated flow identifier in the external API management system (a UUID, not a Celigo flow _id). Empty when no flow is associated."},"status":{"type":"string","enum":["oaspending","published"],"description":"Publication status."},"definitionVersion":{"type":"string","enum":["v4"],"description":"API definition format version."}}}},"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/apis":{"get":{"summary":"List APIs","description":"Returns the APIs configured in the account, cursor-paginated via the `Link` header when\n`limit` is set. Legacy script-mode APIs (created before the builder/script distinction) may\nomit `type`, `version`, and `disabled`. A 204 response means nothing matched.","operationId":"listApis","tags":["APIs"],"parameters":[{"name":"limit","in":"query","description":"Maximum number of records to return per page.","schema":{"type":"integer","minimum":1}},{"name":"name","in":"query","description":"Filter to APIs whose name contains this value — a case-insensitive\nsubstring match, not an exact match; regex metacharacters match\nliterally and surrounding whitespace is trimmed. An empty value is\nignored; a value longer than the maximum is rejected with 400\n`invalid_query_param`.","schema":{"type":"string","maxLength":100}},{"name":"disabled","in":"query","description":"Filter by the `disabled` flag.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"Successfully retrieved list of APIs.","headers":{"Link":{"description":"RFC-5988 pagination links. When more pages remain, includes a `<...>; rel=\"next\"` entry;\nabsent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/API"}}}}},"204":{"description":"No APIs match — the account has none, or the filters excluded every API."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Create an API

> Creates a new API. For \`script\` mode, include \`script.\_scriptId\` and \`script.function\` (the\
> server also copies these to the top level in the response). For \`builder\` mode,\
> \`builder.request\` can be added later — an API created without it has no route until\
> \`relativeURI\` and \`method\` are set — but when it is present it must carry both, or the\
> request fails with 422 \`invalid\_api\_builder\_request\`.\
> \
> Builder-mode APIs are created with \`logging: {"mode": "basic"}\` when the account license\
> has logging enabled -- the request body cannot override this (\`logging\` is ignored on POST\
> and PUT; change it afterwards with \`PATCH /v1/apis/{\_id}\`).

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Request body for creating or updating an API.\n\nFor builder-mode APIs, populate the `builder` object; the `script` field is\nignored. `builder.request` can be omitted on create — the API has no route\nuntil `relativeURI` and `method` are set — but when it is present it must\ncarry both, or the write fails with 422 `invalid_api_builder_request`. For\nscript-mode APIs, populate `script` with `_scriptId` and `function`; the\n`builder` field is ignored. On PUT, send the complete object — omitted\nfields revert to defaults.\n\nSet `type` explicitly to `builder` or `script`. The server infers `script`\nwhen `type` is omitted, but new APIs must declare it.","required":["name","type"],"allOf":[{"$ref":"#/components/schemas/APIBase"}]},"APIBase":{"type":"object","description":"Writable fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this API belongs to. **Builder mode only** — a script-mode\nAPI is always account-level and the server silently drops this field.\nSend `null` (or omit) to keep the API account-level; on reads the field\nis omitted when unset, never `null`."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"One of the owning integration's `apiGroupings`, subdividing its APIs.\nRequires `_integrationId` in the same write — sent without it, the server\nsilently drops both — so builder mode only. `PUT /v1/apis/updateApiGrouping`\nregroups many APIs at once; this field carries the same value on a single\nAPI. On reads the field is omitted when unset, never `null`."},"description":{"type":"string","description":"Optional description of the API's purpose."},"type":{"type":"string","enum":["builder","script"],"default":"script","description":"API mode. Cannot be changed after creation. Defaults to `script` when\nomitted on create; legacy script APIs created before builder mode may\nomit it on reads as well."},"version":{"type":"string","default":"v1","pattern":"^[a-zA-Z0-9\\-_\\.]+$","description":"Version segment of the public URL (`/apis/{version}{relativeURI}`)."},"disabled":{"type":"boolean","default":false,"description":"When true, the API rejects all incoming requests."},"timeoutPeriod":{"type":"integer","minimum":0,"maximum":120,"description":"Request-timeout override in seconds (1–120). `0` is a sentinel meaning \"use the\n120-second default\" — the server rewrites it on write, so a stored value is never 0."},"logging":{"type":"object","description":"Execution-logging settings for the API. Builder-mode APIs are\ninitialized to `{\"mode\": \"basic\"}` at creation (when the account\nlicense has logging enabled), so the field is present on responses\nfrom the start.\n\nPOST and PUT bodies cannot set or change this field — the server\nignores it silently (the write succeeds and the stored value is\nuntouched). `PATCH /v1/apis/{_id}` with the `/logging/mode` and\n`/logging/debugUntil` paths is the only way to change it.","properties":{"mode":{"type":"string","enum":["basic","standard","detailed","accountLevel","noLogging"],"description":"Which logging level applies to requests handled by this API. Every\nmode that logs records the step list that\n`GET /v1/apis/{_id}/requests/{executionId}` returns, `basic` included;\nthe level decides how much per-record payload the log-data query can\nreturn. Payload-capturing modes (`standard`, `detailed`) require payload\nstorage to be enabled for the account — without it, changing the\nmode fails with `422` (code `payload_storage_required`)."},"debugUntil":{"type":"string","format":"date-time","description":"While this timestamp is in the future, requests are captured in\nfull debug mode regardless of `mode`. Clears itself once the\nwindow passes. Setting it requires payload storage to be enabled\nfor the account."}}},"traceKeyTemplate":{"type":"string","maxLength":1024,"description":"Handlebars template that computes each request's trace key from the\nrequest payload, used to correlate run-history entries with source\nrecords. Absent from responses until set."},"pagination":{"type":"object","description":"Cursor pagination for builder-mode APIs. The first lookup (export\nstep) in `builder.routers` is the volume driver: when pagination is\nenabled, each call to the public endpoint returns one source page of\nthat lookup instead of draining it. The mapped response body keeps its\nown keys at the root and gains one reserved `pagination` object,\n`{\"has_more\": boolean, \"next_cursor\": string}` — no `data` wrapper.\n`next_cursor` is present only while `has_more` is true, and a page\nthat maps to no records is just `{\"pagination\": {\"has_more\": false}}`.\nA root-level `pagination` mapping in the success response is\noverwritten by the platform object at runtime.\n\nCallers fetch the next page by resending the request unchanged with\nthe cursor in the `Celigo-Next-Cursor` request header — for every\nHTTP method; a `next_cursor` field in the request body is ordinary\npayload, not a cursor. Resending a cursor returns the same page again.\nCursor faults fail the invocation with `400`:\n`invalid_cursor_format`, `cursor_signature_invalid` (the cursor was\naltered), `cursor_version_unsupported`, `cursor_api_mismatch` (the\ncursor was issued by a different API), `cursor_filter_mismatch` (the\npath, query, or body differs from the request that issued the cursor),\nor `cursor_not_supported_for_api` (a cursor sent to an API whose\npagination is off). Cursors expire and are then rejected with `410\ncursor_expired`; a response hook that turns the mapped body into a\nnon-object fails with `422 api_pagination_response_not_object`.\n\nSaving the volume-driver export — even with no changes — invalidates\nevery cursor issued so far: the next call with one returns `200` with\nan empty final page, `{\"pagination\": {\"has_more\": false}}`, as if the\nsource were exhausted; restart from the first page without a cursor.\nSaving the API document itself leaves issued cursors valid.\nA success response whose `statusCode` is `204` returns no body, so the\n`pagination` object and cursor are lost with it — a paginated API\nneeds a body-bearing success status.\n\nAbsent from responses until set. A PUT that omits `pagination` keeps\nthe stored value; send `{\"enabled\": null}` to clear it (the field is\nthen absent again).","properties":{"enabled":{"type":"boolean","description":"When true, invocations return one volume-driver page per request\nplus the reserved `pagination` object, and accept the\n`Celigo-Next-Cursor` header. Saving `true` requires a builder-mode\nAPI whose first lookup is an HTTP, Salesforce, or NetSuite export\nwith source paging configured; otherwise the write fails with\n`422` `api_pagination_no_volume_driver` (no lookup at all),\n`api_pagination_adapter_not_supported` (any other adaptor), or\n`api_pagination_source_not_paged` (lookup without paging). The\nsame check repeats on every later save of the API and at every\ninvocation while the stored value is true: if the volume driver\nloses its paging afterwards (the export save itself succeeds),\nevery call fails with `400 api_pagination_source_not_paged` and\nevery PUT or PATCH of the API — including one that omits\n`pagination` — is refused with the `422` until paging is restored\nor this flag is set to false. When false, a `Celigo-Next-Cursor`\nheader is rejected with `400 cursor_not_supported_for_api`."}}},"script":{"$ref":"#/components/schemas/Script"},"builder":{"$ref":"#/components/schemas/Builder"},"shipworks":{"$ref":"#/components/schemas/Shipworks"},"draft":{"type":"boolean","description":"When true, this API is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."}}},"Script":{"type":"object","description":"Script-mode configuration. Callers reach the API at `/v1/apis/{_id}/request`, and the\nreferenced function is called with one `options` object: `method`, `headers` (the\nrequest's headers, without `Authorization`), `queryString` (the parsed query string),\n`body`, and `rawBody` (the body as received, a string). On a GET, `body` is absent and\n`rawBody` is empty. It returns `{statusCode, headers, body}`: `headers` is optional,\nand `body` may be any JSON value, an array included.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource containing the handler function."},"function":{"type":"string","description":"Name of the function to invoke within the script."}},"required":["_scriptId","function"]},"Builder":{"type":"object","description":"Builder-mode configuration defining request structure, routing, and response mapping.","properties":{"request":{"$ref":"#/components/schemas/ApiRequest"},"routers":{"type":"array","description":"Optional routers for conditional processing before the response stage.","items":{"$ref":"#/components/schemas/Router"}},"responseRouter":{"$ref":"#/components/schemas/ResponseRouter"},"responses":{"type":"array","description":"Response configurations. Must include exactly one `success` and one `fail`\nresponse; additional `custom` responses are optional. Order matters: the response\nrouter returns the first response whose `inputFilter` matches, and a response without\none matches every request.","items":{"$ref":"#/components/schemas/ApiResponse"}}}},"ApiRequest":{"type":"object","description":"Request configuration for a builder-mode API endpoint.","properties":{"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9:_*\\/\\-\\.]*$","description":"URI path relative to the version. Callers reach the API at\n`https://api.integrator.io/apis/{version}{relativeURI}` (on the account's regional\nhost outside the US), with the account's API token. Use colon notation for path\nparams: `/customers/:id`."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method for the API endpoint."},"headers":{"type":"array","description":"Expected request headers.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"description":{"type":"string","maxLength":10240,"description":"Description of the header's purpose"}}}},"pathParams":{"type":"array","description":"Path parameters defined in the `relativeURI`.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"description":"Parameter name (without the colon prefix)"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"queryParams":{"type":"array","description":"Expected query string parameters.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_\\-:\\/]*$","description":"Query parameter name"},"dataType":{"type":"string","enum":["string","number","boolean"],"description":"Expected data type of the parameter"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the expected request body structure. Every\nobject-typed schema node must declare at least one property for the\nAPI Builder to render it; omit this field when the endpoint has no\nbody contract.","additionalProperties":true},"mockRequest":{"type":"object","description":"Sample request saved with the API for testing. `POST /v1/apis/{_id}/test/run` doesn't\nread it; send it as that call's `mockRequest`. A test run still makes outside calls: a\nlookup with no saved `mockOutput` calls its source live, and the run saves that response\nas the lookup's `mockOutput`, which later test runs answer from.","properties":{"body":{"type":"object","description":"Sample request body"},"headers":{"type":"object","description":"Sample headers"},"pathParams":{"type":"object","description":"Sample path parameters"},"queryParams":{"type":"object","description":"Sample query parameters"}},"additionalProperties":false},"transform":{"type":"object","description":"Optional transformation applied to the incoming request before processing. The\nexpression form (`type: \"expression\"` with Transformation 2.0 rules in `expression`)\nsaves and runs. In a test run its rules see only the request body, not `pathParams`,\n`queryParams` or headers.","properties":{"type":{"type":"string","description":"Selects the transform form; `expression` runs the rules in `expression`."},"expression":{"type":"object","description":"Transformation 2.0 rules applied to the request body.","properties":{"version":{"type":"string","description":"Rule format; `\"2\"` selects the rules in `rulesTwoDotZero`."},"rulesTwoDotZero":{"type":"object","description":"The rules applied to the request body.","properties":{"mode":{"type":"string","enum":["create","modify"],"description":"How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones."},"mappings":{"type":"array","description":"Mapper 2.0 rows that write fields onto the record.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}}}}}}},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a script for custom transformation logic."},"function":{"type":"string","description":"Function name in the script to execute."}}}},"required":["relativeURI","method"]},"items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}},"Router":{"type":"object","description":"Conditional routing within a builder-mode API. Unlike flows, APIs only\nsupport `first_matching_branch` routing.\n\nA router comes in two shapes, told apart by whether `routeRecordsTo` and\n`routeRecordsUsing` are set: a **branching router** sets both and has two or\nmore branches, each taking the requests its `inputFilter` (or the router's\n`script`) matches — the node you see in the API builder; a **pass-through\nrouter** sets neither and has exactly one branch that every request goes\nstraight through — not drawn, it holds the steps before the first branching\nrouter and merges branches back into shared steps (branches rejoin only by\npointing `nextRouterId` at the same router).","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the API. Use at most 36 letters, digits,\nunderscores and hyphens: a longer id fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the router\nid.\"), as on flow routers."},"name":{"type":"string","description":"Display name."},"routeRecordsTo":{"type":"string","enum":["first_matching_branch"],"description":"Routing strategy; APIs only support `first_matching_branch`. Set together with\n`routeRecordsUsing` on a branching router; leave both unset on a one-branch\npass-through router."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"How a branching router decides which branch a request matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router."},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the branch name."}}},"branches":{"type":"array","description":"Processing branches, evaluated in order.","items":{"type":"object","properties":{"name":{"type":"string","description":"Branch name"},"inputFilter":{"type":"object","description":"Filter criteria for branch selection. Send `version` and `rules` directly on\n`inputFilter` — not inside the `{type: \"expression\", expression: {...}}` wrapper\nthat export and import filters use. A wrapped filter is saved without an error,\nbut the branch is stored with no `inputFilter` and takes every request.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"nextRouterId":{"type":"string","description":"Next router to chain to, or \"apiRouter\" for the response router. Every branch needs\none: a branch without it is saved, but every test run of the API is then refused\nwith 400 \"One or more branches are not merged back. Review the setup to ensure all\nbranches converge.\", whichever branch the request takes. An id that names no router\nfails the save with 422 \"Invalid nextRouterId is defined on the branch. Please\ncorrect the branch configuration.\""},"pageProcessors":{"type":"array","description":"Processing steps to execute in this branch. An export is a step at most once in an\nAPI: using it again, on another branch or in the same one, fails the save with 422\n\"The export <id> is already included as a lookup in your API and cannot be added\nagain.\"","items":{"type":"object","properties":{"type":{"type":"string","enum":["export","import"],"description":"Type of processor"},"_exportId":{"type":"string","format":"objectId","description":"Export resource reference (when type=\"export\")."},"_importId":{"type":"string","format":"objectId","description":"Import resource reference (when type=\"import\")."},"hooks":{"type":"object","description":"Custom scripts for processing"},"proceedOnFailure":{"type":"boolean","description":"When true, the next step still runs after this step fails, and the request\ncan still end in the `success` response (`context.success` stays true).\nWhen false, a failure stops the branch and the API returns its `fail`\nresponse."}}}}}}}},"required":["branches"]},"ResponseRouter":{"type":"object","description":"Final routing step that selects which response configuration to return.\nMust have `id: \"apiRouter\"`.","properties":{"id":{"type":"string","enum":["apiRouter"],"description":"Must be `\"apiRouter\"`."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Method used to determine which response to use."},"script":{"type":"object","description":"Script configuration when `routeRecordsUsing` is `\"script\"`.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the response id."}}}}},"ApiResponse":{"type":"object","description":"Response configuration in a builder-mode API. Each API requires exactly one\n`success` and one `fail` response; additional `custom` responses are optional.","properties":{"id":{"type":"string","description":"Unique identifier for this response, referenced by the response router."},"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description of when this response is used."},"type":{"type":"string","enum":["success","fail","custom"],"description":"Response type. `success` isn't a fallback checked after the `custom` responses: list\n`custom` responses before it (see `inputFilter`)."},"statusCode":{"type":"integer","minimum":100,"maximum":599,"description":"HTTP status code to return."},"headers":{"type":"array","description":"Response headers to include.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"value":{"type":"string","maxLength":256,"description":"Header value (can include handlebars templates)"},"description":{"type":"string","maxLength":10240,"description":"Description of the header"}}}},"inputFilter":{"type":"object","description":"Filter criteria for response selection by the response router, which returns the first\nresponse in `responses` whose filter matches. A response without an `inputFilter` matches\nevery request, so a `success` listed first answers requests a later `custom` filter\nmatches; the typed `context.success` filter doesn't prevent that, because\n`context.success` is true whenever no step failed, including when a lookup found nothing.\nA step that fails with `proceedOnFailure` off selects the `fail` response.\n\nSend `version` and `rules` directly on `inputFilter`, not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import filters use. A\nwrapped filter is saved without an error, but the response is stored with no\n`inputFilter`, so it matches every request that reaches it.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the response body structure. Every object-typed\nschema node must declare at least one property for the API Builder to\nrender it; omit this field when the response body has no defined shape.","additionalProperties":true},"mockInput":{"type":["object","string"],"maxLength":0,"description":"Mock data for testing this response, in the integrator.io canonical\nrecord-page format: `{\"page_of_records\": [{\"record\": {...}}, ...]}`.\nThe server rejects any other object shape and any non-empty string\nwith a 422; the empty string `\"\"` (a UI draft artifact) is accepted\nand stored verbatim.","required":["page_of_records"],"properties":{"page_of_records":{"type":"array","description":"Pages of mock records fed to this response's mappings.","items":{"type":"object","required":["record"],"properties":{"record":{"type":"object","description":"One mock input record (freeform payload)."},"success":{"type":"boolean","description":"When true, the mock record follows the success path."},"testMode":{"type":"boolean","description":"When true, the mock record is treated as a test-mode record."}}}}},"additionalProperties":true},"mappings":{"type":"array","description":"Mapper 2.0 rows that build the response body from the record the steps produced,\nunder the same rules as the shared Mapper 2.0 schema an import's `mappings` use.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}}},"lookups":{"type":"array","description":"Static key-value lookup tables for value transformation.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the lookup"},"map":{"type":"object","description":"Key-value mapping object"},"default":{"type":"string","description":"Default value if key not found"},"allowFailures":{"type":"boolean","description":"When true, processing continues even if this lookup fails."}}}},"hooks":{"type":"object","description":"Custom scripts to run during response processing.","properties":{"preMap":{"type":"object","description":"Script to run before applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}},"postMap":{"type":"object","description":"Script to run after applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}}}}}},"items-2":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}},"Shipworks":{"type":"object","description":"ShipWorks shipping-management credentials. Legacy feature.","properties":{"username":{"type":"string","description":"ShipWorks username."},"password":{"type":"string","description":"ShipWorks password. Masked as `\"******\"` in GET responses."}},"required":["username","password"]},"API":{"required":["_id","name","createdAt","lastModified"],"description":"API resource. Shape varies by mode: builder-mode APIs carry `type`, `version`,\n`disabled`, and `builder`; script-mode APIs additionally carry `script` plus\ntop-level `_scriptId` / `function` copies. Legacy script APIs (pre-builder era)\nomit `type`, `version`, `disabled`, and `builder` entirely.","allOf":[{"$ref":"#/components/schemas/APIBase"},{"type":"object","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the API."},"_scriptId":{"type":"string","format":"objectId","readOnly":true,"description":"Top-level copy of `script._scriptId`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"function":{"type":"string","readOnly":true,"description":"Top-level copy of `script.function`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was last modified."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this API was created from. Present only on template-installed APIs."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft API auto-deletes. Server-computed when `draft` is set at\ncreation."},"apim":{"$ref":"#/components/schemas/Apim"}}}]},"Apim":{"type":"array","readOnly":true,"description":"Publication status of this API in external API management systems.","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier assigned by the external API management system (a UUID, not a Celigo API _id)."},"flowId":{"type":"string","description":"Associated flow identifier in the external API management system (a UUID, not a Celigo flow _id). Empty when no flow is associated."},"status":{"type":"string","enum":["oaspending","published"],"description":"Publication status."},"definitionVersion":{"type":"string","enum":["v4"],"description":"API definition format version."}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis":{"post":{"summary":"Create an API","description":"Creates a new API. For `script` mode, include `script._scriptId` and `script.function` (the\nserver also copies these to the top level in the response). For `builder` mode,\n`builder.request` can be added later — an API created without it has no route until\n`relativeURI` and `method` are set — but when it is present it must carry both, or the\nrequest fails with 422 `invalid_api_builder_request`.\n\nBuilder-mode APIs are created with `logging: {\"mode\": \"basic\"}` when the account license\nhas logging enabled -- the request body cannot override this (`logging` is ignored on POST\nand PUT; change it afterwards with `PATCH /v1/apis/{_id}`).","operationId":"createApi","tags":["APIs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"201":{"description":"API created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/API"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List month-to-date API invocation counts

> Returns one invocation-counter record per resource + method + relativeURI in the current month.\
> Counts API-style invocations across every resource type that exposes an HTTP-callable endpoint:\
> custom APIs (builder and script), individual exports/imports called via \`/invoke\`, virtual\
> imports, and APIM-fronted invocations.\
> \
> The endpoint aggregates -- it does not return one record per individual call. Each entry rolls\
> up every invocation of that (resource, method, URI) triple in the current month. Counters reset\
> on the 1st of each month; there is no pagination and no historical-months filter on this path.\
> For month-over-month account totals use \`GET /v1/apis/usage/summary\`; for the current month\
> split by environment use \`GET /v1/apis/usage/environments\`.\
> \
> \`ioInvocationCount\` bills against the Celigo subscription; \`apimInvocationCount\` is billed\
> separately for external APIM passthrough. To find the resource behind a row, read\
> \`metadata.\_resourceId\` (present for exports/imports) or parse the resource id out of\
> \`relativeURI\`.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApisUsageResponse":{"type":"object","description":"Month-to-date invocation counters for every API endpoint that has been called in the account.\nReturned by `GET /v1/apis/usage`. Each entry in `usages[]` represents one resource + method +\nrelativeURI triple — the same export or import invoked via two different methods yields two\nentries. Counters are cumulative for the month named in `month` / `year` and reset on the 1st.","properties":{"usages":{"type":"array","description":"Per-endpoint invocation records. Empty array when the account hasn't invoked any API endpoints\nthis month. Includes entries for every resource that can be invoked as an API —\ncustom APIs, individual exports/imports (`/v1/exports/{id}/invoke`, `/v1/imports/{id}/invoke`),\nvirtual imports, and script APIs.","items":{"$ref":"#/components/schemas/ApisUsageEntry"}},"externalApimCount":{"type":"integer","description":"Account-wide count of invocations that arrived through an external API Management layer\n(APIM) in front of integrator.io for the current month. Aggregate counterpart to the\nper-endpoint `apimInvocationCount` values in `usages[]`. Absent on some responses when the\naccount has never been routed through an external APIM."}}},"ApisUsageEntry":{"type":"object","description":"One month's invocation record for a single API-callable endpoint. Keyed by the\nresource + HTTP method + relativeURI combination — the same export invoked via two HTTP methods\nproduces two separate entries.","properties":{"_id":{"type":"string","format":"objectId","description":"Unique id of this usage record (not the resource id — see `metadata._resourceId`)."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method the endpoint was called with."},"relativeURI":{"type":"string","description":"The endpoint path (relative to `https://api.integrator.io`) that was invoked. Common shapes:\n`/v1/exports/{_exportId}/invoke`, `/v1/imports/{_importId}/invoke`,\n`/v1/connections/{_connectionId}/import` for virtual imports,\n`/v1/apis/{_apiId}/request` for script-mode APIs, and\n`/apis/{version}{relativeURI}` (such as `/apis/v1/orders`) for builder-mode APIs."},"metadata":{"type":"object","description":"Human-readable labeling of the resource behind this usage record.","properties":{"_resourceId":{"type":"string","format":"objectId","description":"Id of the underlying export, import, or API resource. Omitted for some resource types\n(e.g. connection-scoped virtual imports) where the URL itself fully identifies the target."},"name":{"type":"string","description":"Display name of the resource at the time of invocation."},"type":{"type":"string","enum":["export","import","virtualImport","script","apiBuilder"],"description":"Resource flavor. `virtualImport` is a connection-scoped import (connector-embedded).\n`script` is a script-mode API. `apiBuilder` is a builder-mode API."}}},"month":{"type":"integer","minimum":1,"maximum":12,"description":"Calendar month (1 = January) the counters cover."},"year":{"type":"integer","description":"Four-digit year the counters cover."},"ioInvocationCount":{"type":"integer","description":"Number of times the endpoint was invoked through integrator.io's own API front door. This is\nthe counter that bills against the subscription's API invocation entitlement."},"apimInvocationCount":{"type":"integer","description":"Number of times the endpoint was invoked through an external API Management layer (APIM) in\nfront of integrator.io. Billed separately from `ioInvocationCount`."},"createdAt":{"type":"string","format":"date-time","description":"When this monthly counter record was first created (the first invocation of the month)."}}}},"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/apis/usage":{"get":{"operationId":"listApisUsage","tags":["APIs"],"summary":"List month-to-date API invocation counts","description":"Returns one invocation-counter record per resource + method + relativeURI in the current month.\nCounts API-style invocations across every resource type that exposes an HTTP-callable endpoint:\ncustom APIs (builder and script), individual exports/imports called via `/invoke`, virtual\nimports, and APIM-fronted invocations.\n\nThe endpoint aggregates -- it does not return one record per individual call. Each entry rolls\nup every invocation of that (resource, method, URI) triple in the current month. Counters reset\non the 1st of each month; there is no pagination and no historical-months filter on this path.\nFor month-over-month account totals use `GET /v1/apis/usage/summary`; for the current month\nsplit by environment use `GET /v1/apis/usage/environments`.\n\n`ioInvocationCount` bills against the Celigo subscription; `apimInvocationCount` is billed\nseparately for external APIM passthrough. To find the resource behind a row, read\n`metadata._resourceId` (present for exports/imports) or parse the resource id out of\n`relativeURI`.","parameters":[{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"Usage breakdown for the current month. `usages[]` is empty when no endpoints have been invoked yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApisUsageResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## List monthly API invocation totals

> Returns one total per calendar month, newest first, summed across every environment\
> in the account, alongside the invocations the subscription allowed for that month.\
> Use it for trend and overage reporting; \`GET /v1/apis/usage\` gives the per-endpoint\
> breakdown for the current month only.\
> \
> Without \`from\`/\`to\` the response covers the current month and the thirteen before it.\
> Both parameters take \`YYYY/MM\`; the window is capped at fourteen months, \`to\` may not\
> be in the future, and \`from\` may not precede the fourteen-month lookback. A malformed\
> or out-of-range value is not rejected — the server silently falls back to the default\
> window, so check the \`year\`/\`month\` of the first and last entries when passing a range.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApisUsageSummaryEntry":{"type":"object","description":"Account-wide API invocation total for one calendar month, summed across every\nenvironment. Counts are serialized as decimal strings.","required":["year","month","invocationCount","entitlements"],"properties":{"year":{"type":"integer","description":"Four-digit year the total covers."},"month":{"type":"integer","minimum":1,"maximum":12,"description":"Calendar month (1 = January) the total covers."},"invocationCount":{"type":"string","pattern":"^[0-9]+$","description":"Invocations recorded in the month across all environments — integrator.io\nfront-door calls plus calls that arrived through an external API Management\nlayer — as a decimal string. `\"0\"` for months with no traffic."},"entitlements":{"type":"string","pattern":"^[0-9]+$","description":"Invocations the subscription allowed for that month (base plus add-on), as a\ndecimal string. Compare with `invocationCount` to spot overage months. `\"0\"`\nwhen the license carries no API invocation entitlement."}}}},"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/apis/usage/summary":{"get":{"operationId":"listApisUsageSummary","tags":["APIs"],"summary":"List monthly API invocation totals","description":"Returns one total per calendar month, newest first, summed across every environment\nin the account, alongside the invocations the subscription allowed for that month.\nUse it for trend and overage reporting; `GET /v1/apis/usage` gives the per-endpoint\nbreakdown for the current month only.\n\nWithout `from`/`to` the response covers the current month and the thirteen before it.\nBoth parameters take `YYYY/MM`; the window is capped at fourteen months, `to` may not\nbe in the future, and `from` may not precede the fourteen-month lookback. A malformed\nor out-of-range value is not rejected — the server silently falls back to the default\nwindow, so check the `year`/`month` of the first and last entries when passing a range.","parameters":[{"name":"from","in":"query","description":"First month to include, as `YYYY/MM`. Defaults to thirteen months before the current month.","schema":{"type":"string","pattern":"^[0-9]{4}/(0?[1-9]|1[0-2])$"}},{"name":"to","in":"query","description":"Last month to include, as `YYYY/MM`. Defaults to the current month.","schema":{"type":"string","pattern":"^[0-9]{4}/(0?[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"Monthly totals, newest month first. Months without traffic are included with `\"0\"` counts.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApisUsageSummaryEntry"}}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## List current-month API usage per environment

> Returns the current month's invocation counters for every environment in the account,\
> including environments with no traffic. Counters reset on the first of each month.\
> \`GET /v1/apis/usage\` returns the per-endpoint breakdown for the calling environment\
> only; use this operation to compare environments side by side.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApisUsageEnvironmentsResponse":{"type":"object","description":"Current-month API invocation totals broken down by environment, as returned by\n`GET /v1/apis/usage/environments`.","required":["usage"],"properties":{"usage":{"type":"array","description":"One entry per environment in the account, including environments with no traffic.","items":{"type":"object","required":["environment","ioInvocationCount","apimInvocationCount","externalApimCount"],"properties":{"environment":{"type":"object","description":"Environment the counters belong to.","required":["name"],"properties":{"_id":{"type":"string","format":"objectId","description":"Environment id. Present when set — accounts that still use the legacy\nproduction/sandbox split report only `name`."},"name":{"type":"string","description":"Environment display name."}}},"ioInvocationCount":{"type":"integer","description":"Invocations this month through integrator.io's own API front door."},"apimInvocationCount":{"type":"integer","description":"Invocations this month proxied through the external API Management layer."},"externalApimCount":{"type":"integer","description":"Invocations this month that reached the external API Management layer\ndirectly, without passing through integrator.io. Zero when API Management\nis not enabled for the account."}}}}}}},"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/apis/usage/environments":{"get":{"operationId":"listApisUsageByEnvironment","tags":["APIs"],"summary":"List current-month API usage per environment","description":"Returns the current month's invocation counters for every environment in the account,\nincluding environments with no traffic. Counters reset on the first of each month.\n`GET /v1/apis/usage` returns the per-endpoint breakdown for the calling environment\nonly; use this operation to compare environments side by side.","responses":{"200":{"description":"Per-environment counters for the current month.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApisUsageEnvironmentsResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Get an API

> Returns the complete configuration of a specific API.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"API":{"required":["_id","name","createdAt","lastModified"],"description":"API resource. Shape varies by mode: builder-mode APIs carry `type`, `version`,\n`disabled`, and `builder`; script-mode APIs additionally carry `script` plus\ntop-level `_scriptId` / `function` copies. Legacy script APIs (pre-builder era)\nomit `type`, `version`, `disabled`, and `builder` entirely.","allOf":[{"$ref":"#/components/schemas/APIBase"},{"type":"object","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the API."},"_scriptId":{"type":"string","format":"objectId","readOnly":true,"description":"Top-level copy of `script._scriptId`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"function":{"type":"string","readOnly":true,"description":"Top-level copy of `script.function`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was last modified."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this API was created from. Present only on template-installed APIs."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft API auto-deletes. Server-computed when `draft` is set at\ncreation."},"apim":{"$ref":"#/components/schemas/Apim"}}}]},"APIBase":{"type":"object","description":"Writable fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this API belongs to. **Builder mode only** — a script-mode\nAPI is always account-level and the server silently drops this field.\nSend `null` (or omit) to keep the API account-level; on reads the field\nis omitted when unset, never `null`."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"One of the owning integration's `apiGroupings`, subdividing its APIs.\nRequires `_integrationId` in the same write — sent without it, the server\nsilently drops both — so builder mode only. `PUT /v1/apis/updateApiGrouping`\nregroups many APIs at once; this field carries the same value on a single\nAPI. On reads the field is omitted when unset, never `null`."},"description":{"type":"string","description":"Optional description of the API's purpose."},"type":{"type":"string","enum":["builder","script"],"default":"script","description":"API mode. Cannot be changed after creation. Defaults to `script` when\nomitted on create; legacy script APIs created before builder mode may\nomit it on reads as well."},"version":{"type":"string","default":"v1","pattern":"^[a-zA-Z0-9\\-_\\.]+$","description":"Version segment of the public URL (`/apis/{version}{relativeURI}`)."},"disabled":{"type":"boolean","default":false,"description":"When true, the API rejects all incoming requests."},"timeoutPeriod":{"type":"integer","minimum":0,"maximum":120,"description":"Request-timeout override in seconds (1–120). `0` is a sentinel meaning \"use the\n120-second default\" — the server rewrites it on write, so a stored value is never 0."},"logging":{"type":"object","description":"Execution-logging settings for the API. Builder-mode APIs are\ninitialized to `{\"mode\": \"basic\"}` at creation (when the account\nlicense has logging enabled), so the field is present on responses\nfrom the start.\n\nPOST and PUT bodies cannot set or change this field — the server\nignores it silently (the write succeeds and the stored value is\nuntouched). `PATCH /v1/apis/{_id}` with the `/logging/mode` and\n`/logging/debugUntil` paths is the only way to change it.","properties":{"mode":{"type":"string","enum":["basic","standard","detailed","accountLevel","noLogging"],"description":"Which logging level applies to requests handled by this API. Every\nmode that logs records the step list that\n`GET /v1/apis/{_id}/requests/{executionId}` returns, `basic` included;\nthe level decides how much per-record payload the log-data query can\nreturn. Payload-capturing modes (`standard`, `detailed`) require payload\nstorage to be enabled for the account — without it, changing the\nmode fails with `422` (code `payload_storage_required`)."},"debugUntil":{"type":"string","format":"date-time","description":"While this timestamp is in the future, requests are captured in\nfull debug mode regardless of `mode`. Clears itself once the\nwindow passes. Setting it requires payload storage to be enabled\nfor the account."}}},"traceKeyTemplate":{"type":"string","maxLength":1024,"description":"Handlebars template that computes each request's trace key from the\nrequest payload, used to correlate run-history entries with source\nrecords. Absent from responses until set."},"pagination":{"type":"object","description":"Cursor pagination for builder-mode APIs. The first lookup (export\nstep) in `builder.routers` is the volume driver: when pagination is\nenabled, each call to the public endpoint returns one source page of\nthat lookup instead of draining it. The mapped response body keeps its\nown keys at the root and gains one reserved `pagination` object,\n`{\"has_more\": boolean, \"next_cursor\": string}` — no `data` wrapper.\n`next_cursor` is present only while `has_more` is true, and a page\nthat maps to no records is just `{\"pagination\": {\"has_more\": false}}`.\nA root-level `pagination` mapping in the success response is\noverwritten by the platform object at runtime.\n\nCallers fetch the next page by resending the request unchanged with\nthe cursor in the `Celigo-Next-Cursor` request header — for every\nHTTP method; a `next_cursor` field in the request body is ordinary\npayload, not a cursor. Resending a cursor returns the same page again.\nCursor faults fail the invocation with `400`:\n`invalid_cursor_format`, `cursor_signature_invalid` (the cursor was\naltered), `cursor_version_unsupported`, `cursor_api_mismatch` (the\ncursor was issued by a different API), `cursor_filter_mismatch` (the\npath, query, or body differs from the request that issued the cursor),\nor `cursor_not_supported_for_api` (a cursor sent to an API whose\npagination is off). Cursors expire and are then rejected with `410\ncursor_expired`; a response hook that turns the mapped body into a\nnon-object fails with `422 api_pagination_response_not_object`.\n\nSaving the volume-driver export — even with no changes — invalidates\nevery cursor issued so far: the next call with one returns `200` with\nan empty final page, `{\"pagination\": {\"has_more\": false}}`, as if the\nsource were exhausted; restart from the first page without a cursor.\nSaving the API document itself leaves issued cursors valid.\nA success response whose `statusCode` is `204` returns no body, so the\n`pagination` object and cursor are lost with it — a paginated API\nneeds a body-bearing success status.\n\nAbsent from responses until set. A PUT that omits `pagination` keeps\nthe stored value; send `{\"enabled\": null}` to clear it (the field is\nthen absent again).","properties":{"enabled":{"type":"boolean","description":"When true, invocations return one volume-driver page per request\nplus the reserved `pagination` object, and accept the\n`Celigo-Next-Cursor` header. Saving `true` requires a builder-mode\nAPI whose first lookup is an HTTP, Salesforce, or NetSuite export\nwith source paging configured; otherwise the write fails with\n`422` `api_pagination_no_volume_driver` (no lookup at all),\n`api_pagination_adapter_not_supported` (any other adaptor), or\n`api_pagination_source_not_paged` (lookup without paging). The\nsame check repeats on every later save of the API and at every\ninvocation while the stored value is true: if the volume driver\nloses its paging afterwards (the export save itself succeeds),\nevery call fails with `400 api_pagination_source_not_paged` and\nevery PUT or PATCH of the API — including one that omits\n`pagination` — is refused with the `422` until paging is restored\nor this flag is set to false. When false, a `Celigo-Next-Cursor`\nheader is rejected with `400 cursor_not_supported_for_api`."}}},"script":{"$ref":"#/components/schemas/Script"},"builder":{"$ref":"#/components/schemas/Builder"},"shipworks":{"$ref":"#/components/schemas/Shipworks"},"draft":{"type":"boolean","description":"When true, this API is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."}}},"Script":{"type":"object","description":"Script-mode configuration. Callers reach the API at `/v1/apis/{_id}/request`, and the\nreferenced function is called with one `options` object: `method`, `headers` (the\nrequest's headers, without `Authorization`), `queryString` (the parsed query string),\n`body`, and `rawBody` (the body as received, a string). On a GET, `body` is absent and\n`rawBody` is empty. It returns `{statusCode, headers, body}`: `headers` is optional,\nand `body` may be any JSON value, an array included.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource containing the handler function."},"function":{"type":"string","description":"Name of the function to invoke within the script."}},"required":["_scriptId","function"]},"Builder":{"type":"object","description":"Builder-mode configuration defining request structure, routing, and response mapping.","properties":{"request":{"$ref":"#/components/schemas/ApiRequest"},"routers":{"type":"array","description":"Optional routers for conditional processing before the response stage.","items":{"$ref":"#/components/schemas/Router"}},"responseRouter":{"$ref":"#/components/schemas/ResponseRouter"},"responses":{"type":"array","description":"Response configurations. Must include exactly one `success` and one `fail`\nresponse; additional `custom` responses are optional. Order matters: the response\nrouter returns the first response whose `inputFilter` matches, and a response without\none matches every request.","items":{"$ref":"#/components/schemas/ApiResponse"}}}},"ApiRequest":{"type":"object","description":"Request configuration for a builder-mode API endpoint.","properties":{"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9:_*\\/\\-\\.]*$","description":"URI path relative to the version. Callers reach the API at\n`https://api.integrator.io/apis/{version}{relativeURI}` (on the account's regional\nhost outside the US), with the account's API token. Use colon notation for path\nparams: `/customers/:id`."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method for the API endpoint."},"headers":{"type":"array","description":"Expected request headers.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"description":{"type":"string","maxLength":10240,"description":"Description of the header's purpose"}}}},"pathParams":{"type":"array","description":"Path parameters defined in the `relativeURI`.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"description":"Parameter name (without the colon prefix)"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"queryParams":{"type":"array","description":"Expected query string parameters.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_\\-:\\/]*$","description":"Query parameter name"},"dataType":{"type":"string","enum":["string","number","boolean"],"description":"Expected data type of the parameter"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the expected request body structure. Every\nobject-typed schema node must declare at least one property for the\nAPI Builder to render it; omit this field when the endpoint has no\nbody contract.","additionalProperties":true},"mockRequest":{"type":"object","description":"Sample request saved with the API for testing. `POST /v1/apis/{_id}/test/run` doesn't\nread it; send it as that call's `mockRequest`. A test run still makes outside calls: a\nlookup with no saved `mockOutput` calls its source live, and the run saves that response\nas the lookup's `mockOutput`, which later test runs answer from.","properties":{"body":{"type":"object","description":"Sample request body"},"headers":{"type":"object","description":"Sample headers"},"pathParams":{"type":"object","description":"Sample path parameters"},"queryParams":{"type":"object","description":"Sample query parameters"}},"additionalProperties":false},"transform":{"type":"object","description":"Optional transformation applied to the incoming request before processing. The\nexpression form (`type: \"expression\"` with Transformation 2.0 rules in `expression`)\nsaves and runs. In a test run its rules see only the request body, not `pathParams`,\n`queryParams` or headers.","properties":{"type":{"type":"string","description":"Selects the transform form; `expression` runs the rules in `expression`."},"expression":{"type":"object","description":"Transformation 2.0 rules applied to the request body.","properties":{"version":{"type":"string","description":"Rule format; `\"2\"` selects the rules in `rulesTwoDotZero`."},"rulesTwoDotZero":{"type":"object","description":"The rules applied to the request body.","properties":{"mode":{"type":"string","enum":["create","modify"],"description":"How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones."},"mappings":{"type":"array","description":"Mapper 2.0 rows that write fields onto the record.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}}}}}}},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a script for custom transformation logic."},"function":{"type":"string","description":"Function name in the script to execute."}}}},"required":["relativeURI","method"]},"items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}},"Router":{"type":"object","description":"Conditional routing within a builder-mode API. Unlike flows, APIs only\nsupport `first_matching_branch` routing.\n\nA router comes in two shapes, told apart by whether `routeRecordsTo` and\n`routeRecordsUsing` are set: a **branching router** sets both and has two or\nmore branches, each taking the requests its `inputFilter` (or the router's\n`script`) matches — the node you see in the API builder; a **pass-through\nrouter** sets neither and has exactly one branch that every request goes\nstraight through — not drawn, it holds the steps before the first branching\nrouter and merges branches back into shared steps (branches rejoin only by\npointing `nextRouterId` at the same router).","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the API. Use at most 36 letters, digits,\nunderscores and hyphens: a longer id fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the router\nid.\"), as on flow routers."},"name":{"type":"string","description":"Display name."},"routeRecordsTo":{"type":"string","enum":["first_matching_branch"],"description":"Routing strategy; APIs only support `first_matching_branch`. Set together with\n`routeRecordsUsing` on a branching router; leave both unset on a one-branch\npass-through router."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"How a branching router decides which branch a request matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router."},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the branch name."}}},"branches":{"type":"array","description":"Processing branches, evaluated in order.","items":{"type":"object","properties":{"name":{"type":"string","description":"Branch name"},"inputFilter":{"type":"object","description":"Filter criteria for branch selection. Send `version` and `rules` directly on\n`inputFilter` — not inside the `{type: \"expression\", expression: {...}}` wrapper\nthat export and import filters use. A wrapped filter is saved without an error,\nbut the branch is stored with no `inputFilter` and takes every request.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"nextRouterId":{"type":"string","description":"Next router to chain to, or \"apiRouter\" for the response router. Every branch needs\none: a branch without it is saved, but every test run of the API is then refused\nwith 400 \"One or more branches are not merged back. Review the setup to ensure all\nbranches converge.\", whichever branch the request takes. An id that names no router\nfails the save with 422 \"Invalid nextRouterId is defined on the branch. Please\ncorrect the branch configuration.\""},"pageProcessors":{"type":"array","description":"Processing steps to execute in this branch. An export is a step at most once in an\nAPI: using it again, on another branch or in the same one, fails the save with 422\n\"The export <id> is already included as a lookup in your API and cannot be added\nagain.\"","items":{"type":"object","properties":{"type":{"type":"string","enum":["export","import"],"description":"Type of processor"},"_exportId":{"type":"string","format":"objectId","description":"Export resource reference (when type=\"export\")."},"_importId":{"type":"string","format":"objectId","description":"Import resource reference (when type=\"import\")."},"hooks":{"type":"object","description":"Custom scripts for processing"},"proceedOnFailure":{"type":"boolean","description":"When true, the next step still runs after this step fails, and the request\ncan still end in the `success` response (`context.success` stays true).\nWhen false, a failure stops the branch and the API returns its `fail`\nresponse."}}}}}}}},"required":["branches"]},"ResponseRouter":{"type":"object","description":"Final routing step that selects which response configuration to return.\nMust have `id: \"apiRouter\"`.","properties":{"id":{"type":"string","enum":["apiRouter"],"description":"Must be `\"apiRouter\"`."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Method used to determine which response to use."},"script":{"type":"object","description":"Script configuration when `routeRecordsUsing` is `\"script\"`.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the response id."}}}}},"ApiResponse":{"type":"object","description":"Response configuration in a builder-mode API. Each API requires exactly one\n`success` and one `fail` response; additional `custom` responses are optional.","properties":{"id":{"type":"string","description":"Unique identifier for this response, referenced by the response router."},"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description of when this response is used."},"type":{"type":"string","enum":["success","fail","custom"],"description":"Response type. `success` isn't a fallback checked after the `custom` responses: list\n`custom` responses before it (see `inputFilter`)."},"statusCode":{"type":"integer","minimum":100,"maximum":599,"description":"HTTP status code to return."},"headers":{"type":"array","description":"Response headers to include.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"value":{"type":"string","maxLength":256,"description":"Header value (can include handlebars templates)"},"description":{"type":"string","maxLength":10240,"description":"Description of the header"}}}},"inputFilter":{"type":"object","description":"Filter criteria for response selection by the response router, which returns the first\nresponse in `responses` whose filter matches. A response without an `inputFilter` matches\nevery request, so a `success` listed first answers requests a later `custom` filter\nmatches; the typed `context.success` filter doesn't prevent that, because\n`context.success` is true whenever no step failed, including when a lookup found nothing.\nA step that fails with `proceedOnFailure` off selects the `fail` response.\n\nSend `version` and `rules` directly on `inputFilter`, not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import filters use. A\nwrapped filter is saved without an error, but the response is stored with no\n`inputFilter`, so it matches every request that reaches it.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the response body structure. Every object-typed\nschema node must declare at least one property for the API Builder to\nrender it; omit this field when the response body has no defined shape.","additionalProperties":true},"mockInput":{"type":["object","string"],"maxLength":0,"description":"Mock data for testing this response, in the integrator.io canonical\nrecord-page format: `{\"page_of_records\": [{\"record\": {...}}, ...]}`.\nThe server rejects any other object shape and any non-empty string\nwith a 422; the empty string `\"\"` (a UI draft artifact) is accepted\nand stored verbatim.","required":["page_of_records"],"properties":{"page_of_records":{"type":"array","description":"Pages of mock records fed to this response's mappings.","items":{"type":"object","required":["record"],"properties":{"record":{"type":"object","description":"One mock input record (freeform payload)."},"success":{"type":"boolean","description":"When true, the mock record follows the success path."},"testMode":{"type":"boolean","description":"When true, the mock record is treated as a test-mode record."}}}}},"additionalProperties":true},"mappings":{"type":"array","description":"Mapper 2.0 rows that build the response body from the record the steps produced,\nunder the same rules as the shared Mapper 2.0 schema an import's `mappings` use.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}}},"lookups":{"type":"array","description":"Static key-value lookup tables for value transformation.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the lookup"},"map":{"type":"object","description":"Key-value mapping object"},"default":{"type":"string","description":"Default value if key not found"},"allowFailures":{"type":"boolean","description":"When true, processing continues even if this lookup fails."}}}},"hooks":{"type":"object","description":"Custom scripts to run during response processing.","properties":{"preMap":{"type":"object","description":"Script to run before applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}},"postMap":{"type":"object","description":"Script to run after applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}}}}}},"items-2":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}},"Shipworks":{"type":"object","description":"ShipWorks shipping-management credentials. Legacy feature.","properties":{"username":{"type":"string","description":"ShipWorks username."},"password":{"type":"string","description":"ShipWorks password. Masked as `\"******\"` in GET responses."}},"required":["username","password"]},"Apim":{"type":"array","readOnly":true,"description":"Publication status of this API in external API management systems.","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier assigned by the external API management system (a UUID, not a Celigo API _id)."},"flowId":{"type":"string","description":"Associated flow identifier in the external API management system (a UUID, not a Celigo flow _id). Empty when no flow is associated."},"status":{"type":"string","enum":["oaspending","published"],"description":"Publication status."},"definitionVersion":{"type":"string","enum":["v4"],"description":"API definition format version."}}}},"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/apis/{_id}":{"get":{"summary":"Get an API","description":"Returns the complete configuration of a specific API.","operationId":"getApiById","tags":["APIs"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the API","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"API retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/API"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Update an API

> Replaces the full API configuration. Send the complete object -- omitted fields revert to\
> defaults, not their prior values. Read-only fields (\`\_id\`, \`createdAt\`, \`lastModified\`) in\
> the request body are ignored.\
> \
> \`logging\` is also ignored -- silently: a PUT that includes \`logging\` succeeds with the\
> stored value unchanged, and no error reveals that the change was dropped. Use\
> \`PATCH /v1/apis/{\_id}\` (paths \`/logging/mode\`, \`/logging/debugUntil\`) to change logging\
> settings.\
> \
> Always send \`disabled: false\` on a builder-mode PUT: a body that omits it leaves the\
> flag unset, and the public endpoint answers \`404 api\_not\_found\` until a PUT sets it\
> again.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Request body for creating or updating an API.\n\nFor builder-mode APIs, populate the `builder` object; the `script` field is\nignored. `builder.request` can be omitted on create — the API has no route\nuntil `relativeURI` and `method` are set — but when it is present it must\ncarry both, or the write fails with 422 `invalid_api_builder_request`. For\nscript-mode APIs, populate `script` with `_scriptId` and `function`; the\n`builder` field is ignored. On PUT, send the complete object — omitted\nfields revert to defaults.\n\nSet `type` explicitly to `builder` or `script`. The server infers `script`\nwhen `type` is omitted, but new APIs must declare it.","required":["name","type"],"allOf":[{"$ref":"#/components/schemas/APIBase"}]},"APIBase":{"type":"object","description":"Writable fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this API belongs to. **Builder mode only** — a script-mode\nAPI is always account-level and the server silently drops this field.\nSend `null` (or omit) to keep the API account-level; on reads the field\nis omitted when unset, never `null`."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"One of the owning integration's `apiGroupings`, subdividing its APIs.\nRequires `_integrationId` in the same write — sent without it, the server\nsilently drops both — so builder mode only. `PUT /v1/apis/updateApiGrouping`\nregroups many APIs at once; this field carries the same value on a single\nAPI. On reads the field is omitted when unset, never `null`."},"description":{"type":"string","description":"Optional description of the API's purpose."},"type":{"type":"string","enum":["builder","script"],"default":"script","description":"API mode. Cannot be changed after creation. Defaults to `script` when\nomitted on create; legacy script APIs created before builder mode may\nomit it on reads as well."},"version":{"type":"string","default":"v1","pattern":"^[a-zA-Z0-9\\-_\\.]+$","description":"Version segment of the public URL (`/apis/{version}{relativeURI}`)."},"disabled":{"type":"boolean","default":false,"description":"When true, the API rejects all incoming requests."},"timeoutPeriod":{"type":"integer","minimum":0,"maximum":120,"description":"Request-timeout override in seconds (1–120). `0` is a sentinel meaning \"use the\n120-second default\" — the server rewrites it on write, so a stored value is never 0."},"logging":{"type":"object","description":"Execution-logging settings for the API. Builder-mode APIs are\ninitialized to `{\"mode\": \"basic\"}` at creation (when the account\nlicense has logging enabled), so the field is present on responses\nfrom the start.\n\nPOST and PUT bodies cannot set or change this field — the server\nignores it silently (the write succeeds and the stored value is\nuntouched). `PATCH /v1/apis/{_id}` with the `/logging/mode` and\n`/logging/debugUntil` paths is the only way to change it.","properties":{"mode":{"type":"string","enum":["basic","standard","detailed","accountLevel","noLogging"],"description":"Which logging level applies to requests handled by this API. Every\nmode that logs records the step list that\n`GET /v1/apis/{_id}/requests/{executionId}` returns, `basic` included;\nthe level decides how much per-record payload the log-data query can\nreturn. Payload-capturing modes (`standard`, `detailed`) require payload\nstorage to be enabled for the account — without it, changing the\nmode fails with `422` (code `payload_storage_required`)."},"debugUntil":{"type":"string","format":"date-time","description":"While this timestamp is in the future, requests are captured in\nfull debug mode regardless of `mode`. Clears itself once the\nwindow passes. Setting it requires payload storage to be enabled\nfor the account."}}},"traceKeyTemplate":{"type":"string","maxLength":1024,"description":"Handlebars template that computes each request's trace key from the\nrequest payload, used to correlate run-history entries with source\nrecords. Absent from responses until set."},"pagination":{"type":"object","description":"Cursor pagination for builder-mode APIs. The first lookup (export\nstep) in `builder.routers` is the volume driver: when pagination is\nenabled, each call to the public endpoint returns one source page of\nthat lookup instead of draining it. The mapped response body keeps its\nown keys at the root and gains one reserved `pagination` object,\n`{\"has_more\": boolean, \"next_cursor\": string}` — no `data` wrapper.\n`next_cursor` is present only while `has_more` is true, and a page\nthat maps to no records is just `{\"pagination\": {\"has_more\": false}}`.\nA root-level `pagination` mapping in the success response is\noverwritten by the platform object at runtime.\n\nCallers fetch the next page by resending the request unchanged with\nthe cursor in the `Celigo-Next-Cursor` request header — for every\nHTTP method; a `next_cursor` field in the request body is ordinary\npayload, not a cursor. Resending a cursor returns the same page again.\nCursor faults fail the invocation with `400`:\n`invalid_cursor_format`, `cursor_signature_invalid` (the cursor was\naltered), `cursor_version_unsupported`, `cursor_api_mismatch` (the\ncursor was issued by a different API), `cursor_filter_mismatch` (the\npath, query, or body differs from the request that issued the cursor),\nor `cursor_not_supported_for_api` (a cursor sent to an API whose\npagination is off). Cursors expire and are then rejected with `410\ncursor_expired`; a response hook that turns the mapped body into a\nnon-object fails with `422 api_pagination_response_not_object`.\n\nSaving the volume-driver export — even with no changes — invalidates\nevery cursor issued so far: the next call with one returns `200` with\nan empty final page, `{\"pagination\": {\"has_more\": false}}`, as if the\nsource were exhausted; restart from the first page without a cursor.\nSaving the API document itself leaves issued cursors valid.\nA success response whose `statusCode` is `204` returns no body, so the\n`pagination` object and cursor are lost with it — a paginated API\nneeds a body-bearing success status.\n\nAbsent from responses until set. A PUT that omits `pagination` keeps\nthe stored value; send `{\"enabled\": null}` to clear it (the field is\nthen absent again).","properties":{"enabled":{"type":"boolean","description":"When true, invocations return one volume-driver page per request\nplus the reserved `pagination` object, and accept the\n`Celigo-Next-Cursor` header. Saving `true` requires a builder-mode\nAPI whose first lookup is an HTTP, Salesforce, or NetSuite export\nwith source paging configured; otherwise the write fails with\n`422` `api_pagination_no_volume_driver` (no lookup at all),\n`api_pagination_adapter_not_supported` (any other adaptor), or\n`api_pagination_source_not_paged` (lookup without paging). The\nsame check repeats on every later save of the API and at every\ninvocation while the stored value is true: if the volume driver\nloses its paging afterwards (the export save itself succeeds),\nevery call fails with `400 api_pagination_source_not_paged` and\nevery PUT or PATCH of the API — including one that omits\n`pagination` — is refused with the `422` until paging is restored\nor this flag is set to false. When false, a `Celigo-Next-Cursor`\nheader is rejected with `400 cursor_not_supported_for_api`."}}},"script":{"$ref":"#/components/schemas/Script"},"builder":{"$ref":"#/components/schemas/Builder"},"shipworks":{"$ref":"#/components/schemas/Shipworks"},"draft":{"type":"boolean","description":"When true, this API is a draft that auto-deletes when its expiry passes\n(`draftExpiresAt` in the response). Set at creation; an update can clear the\nflag but never set it."}}},"Script":{"type":"object","description":"Script-mode configuration. Callers reach the API at `/v1/apis/{_id}/request`, and the\nreferenced function is called with one `options` object: `method`, `headers` (the\nrequest's headers, without `Authorization`), `queryString` (the parsed query string),\n`body`, and `rawBody` (the body as received, a string). On a GET, `body` is absent and\n`rawBody` is empty. It returns `{statusCode, headers, body}`: `headers` is optional,\nand `body` may be any JSON value, an array included.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource containing the handler function."},"function":{"type":"string","description":"Name of the function to invoke within the script."}},"required":["_scriptId","function"]},"Builder":{"type":"object","description":"Builder-mode configuration defining request structure, routing, and response mapping.","properties":{"request":{"$ref":"#/components/schemas/ApiRequest"},"routers":{"type":"array","description":"Optional routers for conditional processing before the response stage.","items":{"$ref":"#/components/schemas/Router"}},"responseRouter":{"$ref":"#/components/schemas/ResponseRouter"},"responses":{"type":"array","description":"Response configurations. Must include exactly one `success` and one `fail`\nresponse; additional `custom` responses are optional. Order matters: the response\nrouter returns the first response whose `inputFilter` matches, and a response without\none matches every request.","items":{"$ref":"#/components/schemas/ApiResponse"}}}},"ApiRequest":{"type":"object","description":"Request configuration for a builder-mode API endpoint.","properties":{"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9:_*\\/\\-\\.]*$","description":"URI path relative to the version. Callers reach the API at\n`https://api.integrator.io/apis/{version}{relativeURI}` (on the account's regional\nhost outside the US), with the account's API token. Use colon notation for path\nparams: `/customers/:id`."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"description":"HTTP method for the API endpoint."},"headers":{"type":"array","description":"Expected request headers.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"description":{"type":"string","maxLength":10240,"description":"Description of the header's purpose"}}}},"pathParams":{"type":"array","description":"Path parameters defined in the `relativeURI`.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"description":"Parameter name (without the colon prefix)"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"queryParams":{"type":"array","description":"Expected query string parameters.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_\\-:\\/]*$","description":"Query parameter name"},"dataType":{"type":"string","enum":["string","number","boolean"],"description":"Expected data type of the parameter"},"description":{"type":"string","maxLength":10240,"description":"Description of the parameter"}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the expected request body structure. Every\nobject-typed schema node must declare at least one property for the\nAPI Builder to render it; omit this field when the endpoint has no\nbody contract.","additionalProperties":true},"mockRequest":{"type":"object","description":"Sample request saved with the API for testing. `POST /v1/apis/{_id}/test/run` doesn't\nread it; send it as that call's `mockRequest`. A test run still makes outside calls: a\nlookup with no saved `mockOutput` calls its source live, and the run saves that response\nas the lookup's `mockOutput`, which later test runs answer from.","properties":{"body":{"type":"object","description":"Sample request body"},"headers":{"type":"object","description":"Sample headers"},"pathParams":{"type":"object","description":"Sample path parameters"},"queryParams":{"type":"object","description":"Sample query parameters"}},"additionalProperties":false},"transform":{"type":"object","description":"Optional transformation applied to the incoming request before processing. The\nexpression form (`type: \"expression\"` with Transformation 2.0 rules in `expression`)\nsaves and runs. In a test run its rules see only the request body, not `pathParams`,\n`queryParams` or headers.","properties":{"type":{"type":"string","description":"Selects the transform form; `expression` runs the rules in `expression`."},"expression":{"type":"object","description":"Transformation 2.0 rules applied to the request body.","properties":{"version":{"type":"string","description":"Rule format; `\"2\"` selects the rules in `rulesTwoDotZero`."},"rulesTwoDotZero":{"type":"object","description":"The rules applied to the request body.","properties":{"mode":{"type":"string","enum":["create","modify"],"description":"How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones."},"mappings":{"type":"array","description":"Mapper 2.0 rows that write fields onto the record.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}}}}}}},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a script for custom transformation logic."},"function":{"type":"string","description":"Function name in the script to execute."}}}},"required":["relativeURI","method"]},"items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Record field the row writes."},"extract":{"type":"string","description":"JSONPath into the request body that the value is read from."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type the row writes."},"sourceDataType":{"type":"string","description":"Data type of the extracted value."},"status":{"type":"string","description":"Row status; `Active` rows run."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row.","items":{"$ref":"#/components/schemas/items"}}}},"Router":{"type":"object","description":"Conditional routing within a builder-mode API. Unlike flows, APIs only\nsupport `first_matching_branch` routing.\n\nA router comes in two shapes, told apart by whether `routeRecordsTo` and\n`routeRecordsUsing` are set: a **branching router** sets both and has two or\nmore branches, each taking the requests its `inputFilter` (or the router's\n`script`) matches — the node you see in the API builder; a **pass-through\nrouter** sets neither and has exactly one branch that every request goes\nstraight through — not drawn, it holds the steps before the first branching\nrouter and merges branches back into shared steps (branches rejoin only by\npointing `nextRouterId` at the same router).","properties":{"id":{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$","description":"Unique identifier for this router within the API. Use at most 36 letters, digits,\nunderscores and hyphens: a longer id fails the save with 422 (\"Router id is missing or\ncontains more than 36 characters or invalid characters. Please correct the router\nid.\"), as on flow routers."},"name":{"type":"string","description":"Display name."},"routeRecordsTo":{"type":"string","enum":["first_matching_branch"],"description":"Routing strategy; APIs only support `first_matching_branch`. Set together with\n`routeRecordsUsing` on a branching router; leave both unset on a one-branch\npass-through router."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"How a branching router decides which branch a request matches. Set together with\n`routeRecordsTo`; leave both unset on a one-branch pass-through router."},"script":{"type":"object","description":"Script configuration when routeRecordsUsing=\"script\".\n","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the branch name."}}},"branches":{"type":"array","description":"Processing branches, evaluated in order.","items":{"type":"object","properties":{"name":{"type":"string","description":"Branch name"},"inputFilter":{"type":"object","description":"Filter criteria for branch selection. Send `version` and `rules` directly on\n`inputFilter` — not inside the `{type: \"expression\", expression: {...}}` wrapper\nthat export and import filters use. A wrapped filter is saved without an error,\nbut the branch is stored with no `inputFilter` and takes every request.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"nextRouterId":{"type":"string","description":"Next router to chain to, or \"apiRouter\" for the response router. Every branch needs\none: a branch without it is saved, but every test run of the API is then refused\nwith 400 \"One or more branches are not merged back. Review the setup to ensure all\nbranches converge.\", whichever branch the request takes. An id that names no router\nfails the save with 422 \"Invalid nextRouterId is defined on the branch. Please\ncorrect the branch configuration.\""},"pageProcessors":{"type":"array","description":"Processing steps to execute in this branch. An export is a step at most once in an\nAPI: using it again, on another branch or in the same one, fails the save with 422\n\"The export <id> is already included as a lookup in your API and cannot be added\nagain.\"","items":{"type":"object","properties":{"type":{"type":"string","enum":["export","import"],"description":"Type of processor"},"_exportId":{"type":"string","format":"objectId","description":"Export resource reference (when type=\"export\")."},"_importId":{"type":"string","format":"objectId","description":"Import resource reference (when type=\"import\")."},"hooks":{"type":"object","description":"Custom scripts for processing"},"proceedOnFailure":{"type":"boolean","description":"When true, the next step still runs after this step fails, and the request\ncan still end in the `success` response (`context.success` stays true).\nWhen false, a failure stops the branch and the API returns its `fail`\nresponse."}}}}}}}},"required":["branches"]},"ResponseRouter":{"type":"object","description":"Final routing step that selects which response configuration to return.\nMust have `id: \"apiRouter\"`.","properties":{"id":{"type":"string","enum":["apiRouter"],"description":"Must be `\"apiRouter\"`."},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Method used to determine which response to use."},"script":{"type":"object","description":"Script configuration when `routeRecordsUsing` is `\"script\"`.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name that returns the response id."}}}}},"ApiResponse":{"type":"object","description":"Response configuration in a builder-mode API. Each API requires exactly one\n`success` and one `fail` response; additional `custom` responses are optional.","properties":{"id":{"type":"string","description":"Unique identifier for this response, referenced by the response router."},"name":{"type":"string","maxLength":200,"description":"Display name."},"description":{"type":"string","maxLength":10240,"description":"Optional description of when this response is used."},"type":{"type":"string","enum":["success","fail","custom"],"description":"Response type. `success` isn't a fallback checked after the `custom` responses: list\n`custom` responses before it (see `inputFilter`)."},"statusCode":{"type":"integer","minimum":100,"maximum":599,"description":"HTTP status code to return."},"headers":{"type":"array","description":"Response headers to include.","items":{"type":"object","properties":{"key":{"type":"string","maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$","description":"Header name"},"value":{"type":"string","maxLength":256,"description":"Header value (can include handlebars templates)"},"description":{"type":"string","maxLength":10240,"description":"Description of the header"}}}},"inputFilter":{"type":"object","description":"Filter criteria for response selection by the response router, which returns the first\nresponse in `responses` whose filter matches. A response without an `inputFilter` matches\nevery request, so a `success` listed first answers requests a later `custom` filter\nmatches; the typed `context.success` filter doesn't prevent that, because\n`context.success` is true whenever no step failed, including when a lookup found nothing.\nA step that fails with `proceedOnFailure` off selects the `fail` response.\n\nSend `version` and `rules` directly on `inputFilter`, not inside the\n`{type: \"expression\", expression: {...}}` wrapper that export and import filters use. A\nwrapped filter is saved without an error, but the response is stored with no\n`inputFilter`, so it matches every request that reaches it.","properties":{"version":{"type":"string","enum":["1"],"description":"Version of the filter format used by `rules`."},"rules":{"type":"array","description":"Celigo expression-based filter rules.","items":{}}}},"bodySchema":{"type":"object","description":"JSON Schema describing the response body structure. Every object-typed\nschema node must declare at least one property for the API Builder to\nrender it; omit this field when the response body has no defined shape.","additionalProperties":true},"mockInput":{"type":["object","string"],"maxLength":0,"description":"Mock data for testing this response, in the integrator.io canonical\nrecord-page format: `{\"page_of_records\": [{\"record\": {...}}, ...]}`.\nThe server rejects any other object shape and any non-empty string\nwith a 422; the empty string `\"\"` (a UI draft artifact) is accepted\nand stored verbatim.","required":["page_of_records"],"properties":{"page_of_records":{"type":"array","description":"Pages of mock records fed to this response's mappings.","items":{"type":"object","required":["record"],"properties":{"record":{"type":"object","description":"One mock input record (freeform payload)."},"success":{"type":"boolean","description":"When true, the mock record follows the success path."},"testMode":{"type":"boolean","description":"When true, the mock record is treated as a test-mode record."}}}}},"additionalProperties":true},"mappings":{"type":"array","description":"Mapper 2.0 rows that build the response body from the record the steps produced,\nunder the same rules as the shared Mapper 2.0 schema an import's `mappings` use.","items":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}}},"lookups":{"type":"array","description":"Static key-value lookup tables for value transformation.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the lookup"},"map":{"type":"object","description":"Key-value mapping object"},"default":{"type":"string","description":"Default value if key not found"},"allowFailures":{"type":"boolean","description":"When true, processing continues even if this lookup fails."}}}},"hooks":{"type":"object","description":"Custom scripts to run during response processing.","properties":{"preMap":{"type":"object","description":"Script to run before applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}},"postMap":{"type":"object","description":"Script to run after applying mappings.","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Reference to the script resource."},"function":{"type":"string","description":"Function name to execute."}}}}}}},"items-2":{"type":"object","required":["dataType"],"properties":{"generate":{"type":"string","description":"Name of the response-body field this row writes. A dot doesn't nest:\n`customer.id` makes one key named `customer.id`. To nest, use an `object` row\nwith child `mappings`."},"dataType":{"type":"string","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray"],"description":"Data type of the value this mapping writes into the response body."},"extract":{"type":"string","description":"Where the value comes from, as a JSONPath into the record (`$.id`). A bare string\nsuch as `id` or `record.id` is written as that literal text, not read from the\nrecord."},"mappings":{"type":"array","description":"Child rows of an `object` row, with the same shape as this row. Each writes one\nfield inside the object this row generates.","items":{"$ref":"#/components/schemas/items-2"}},"hardCodedValue":{"type":"string","description":"Static value written to the target field instead of extracting\nfrom input data."}}},"Shipworks":{"type":"object","description":"ShipWorks shipping-management credentials. Legacy feature.","properties":{"username":{"type":"string","description":"ShipWorks username."},"password":{"type":"string","description":"ShipWorks password. Masked as `\"******\"` in GET responses."}},"required":["username","password"]},"API":{"required":["_id","name","createdAt","lastModified"],"description":"API resource. Shape varies by mode: builder-mode APIs carry `type`, `version`,\n`disabled`, and `builder`; script-mode APIs additionally carry `script` plus\ntop-level `_scriptId` / `function` copies. Legacy script APIs (pre-builder era)\nomit `type`, `version`, `disabled`, and `builder` entirely.","allOf":[{"$ref":"#/components/schemas/APIBase"},{"type":"object","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the API."},"_scriptId":{"type":"string","format":"objectId","readOnly":true,"description":"Top-level copy of `script._scriptId`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"function":{"type":"string","readOnly":true,"description":"Top-level copy of `script.function`. Present on script-mode and legacy\nscript APIs for backward compatibility."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the API was last modified."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this API was created from. Present only on template-installed APIs."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when a draft API auto-deletes. Server-computed when `draft` is set at\ncreation."},"apim":{"$ref":"#/components/schemas/Apim"}}}]},"Apim":{"type":"array","readOnly":true,"description":"Publication status of this API in external API management systems.","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier assigned by the external API management system (a UUID, not a Celigo API _id)."},"flowId":{"type":"string","description":"Associated flow identifier in the external API management system (a UUID, not a Celigo flow _id). Empty when no flow is associated."},"status":{"type":"string","enum":["oaspending","published"],"description":"Publication status."},"definitionVersion":{"type":"string","enum":["v4"],"description":"API definition format version."}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}":{"put":{"summary":"Update an API","description":"Replaces the full API configuration. Send the complete object -- omitted fields revert to\ndefaults, not their prior values. Read-only fields (`_id`, `createdAt`, `lastModified`) in\nthe request body are ignored.\n\n`logging` is also ignored -- silently: a PUT that includes `logging` succeeds with the\nstored value unchanged, and no error reveals that the change was dropped. Use\n`PATCH /v1/apis/{_id}` (paths `/logging/mode`, `/logging/debugUntil`) to change logging\nsettings.\n\nAlways send `disabled: false` on a builder-mode PUT: a body that omits it leaves the\nflag unset, and the public endpoint answers `404 api_not_found` until a PUT sets it\nagain.","operationId":"updateApi","tags":["APIs"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the API","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"200":{"description":"API updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/API"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Delete an API

> Deletes an API. Soft-deleted and retained in the recycle bin for 30 days. The public endpoint\
> stops responding immediately. The delete succeeds even with dependents, but those resources\
> will break -- check \`GET /v1/apis/{\_id}/dependencies\` first.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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/apis/{_id}":{"delete":{"summary":"Delete an API","description":"Deletes an API. Soft-deleted and retained in the recycle bin for 30 days. The public endpoint\nstops responding immediately. The delete succeeds even with dependents, but those resources\nwill break -- check `GET /v1/apis/{_id}/dependencies` first.","operationId":"deleteApi","tags":["APIs"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the API","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"API deleted successfully"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Patch an API

> Partially updates an API using a JSON Patch document (RFC 6902).\
> The \`replace\` operation is supported on the following whitelisted\
> paths (\`/logging/debugUntil\` also accepts \`remove\`, which clears an\
> active debug window early):\
> \
> \| Path | Description |\
> \|------|-------------|\
> \| \`/name\` | API display name |\
> \| \`/description\` | API description |\
> \| \`/disabled\` | Enable or disable the API (boolean) |\
> \| \`/timeoutPeriod\` | Request-timeout override in seconds |\
> \| \`/pagination/enabled\` | Enable or disable cursor pagination (boolean; builder-mode only — a script-mode API fails with \`422\` code \`api\_pagination\_builder\_only\`, and enabling re-runs the volume-driver checks described on \`pagination.enabled\`) |\
> \| \`/logging/mode\` | Logging level for requests handled by this API |\
> \| \`/logging/debugUntil\` | End of a temporary full-debug capture window |\
> \| \`/traceKeyTemplate\` | Handlebars template that computes each request's trace key |\
> \
> All other paths are rejected with \`422\`. This is the only way to change\
> \`logging\` -- PUT silently ignores that field.\
> \
> Logging changes are validated against account entitlements: setting\
> \`/logging/mode\` to a payload-capturing mode (\`standard\`, \`detailed\`)\
> fails with \`422\` (code \`payload\_storage\_required\`) when the account\
> does not have payload storage enabled, and \`/logging/debugUntil\` has\
> the same payload-storage requirement. Accounts whose license does not\
> include logging, or whose license caps the maximum logging mode below\
> the requested one, are also rejected with \`422\`.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"JsonPatchRequest":{"type":"array","description":"A JSON Patch document (RFC 6902). Send an array of patch\noperations on whitelisted fields — all other paths are rejected\nwith 422.","minItems":1,"items":{"$ref":"#/components/schemas/JsonPatchOperation"}},"JsonPatchOperation":{"type":"object","description":"A single JSON Patch operation (RFC 6902).","required":["op","path"],"properties":{"op":{"type":"string","enum":["replace","add","remove"],"description":"The operation to perform."},"path":{"type":"string","description":"JSON Pointer (RFC 6901) to the field to patch. Only\nwhitelisted paths are accepted — unlisted paths return\n`422` with `\"<path> is not a whitelisted property\"`."},"value":{"description":"The new value to set. Required for `replace` and `add`, omit for `remove`."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}":{"patch":{"summary":"Patch an API","description":"Partially updates an API using a JSON Patch document (RFC 6902).\nThe `replace` operation is supported on the following whitelisted\npaths (`/logging/debugUntil` also accepts `remove`, which clears an\nactive debug window early):\n\n| Path | Description |\n|------|-------------|\n| `/name` | API display name |\n| `/description` | API description |\n| `/disabled` | Enable or disable the API (boolean) |\n| `/timeoutPeriod` | Request-timeout override in seconds |\n| `/pagination/enabled` | Enable or disable cursor pagination (boolean; builder-mode only — a script-mode API fails with `422` code `api_pagination_builder_only`, and enabling re-runs the volume-driver checks described on `pagination.enabled`) |\n| `/logging/mode` | Logging level for requests handled by this API |\n| `/logging/debugUntil` | End of a temporary full-debug capture window |\n| `/traceKeyTemplate` | Handlebars template that computes each request's trace key |\n\nAll other paths are rejected with `422`. This is the only way to change\n`logging` -- PUT silently ignores that field.\n\nLogging changes are validated against account entitlements: setting\n`/logging/mode` to a payload-capturing mode (`standard`, `detailed`)\nfails with `422` (code `payload_storage_required`) when the account\ndoes not have payload storage enabled, and `/logging/debugUntil` has\nthe same payload-storage requirement. Accounts whose license does not\ninclude logging, or whose license caps the maximum logging mode below\nthe requested one, are also rejected with `422`.","operationId":"patchApi","tags":["APIs"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the API","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonPatchRequest"}}}},"responses":{"204":{"description":"API patched successfully"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Convert a JSON object to JSON Schema

> Accepts a sample JSON object and returns its inferred JSON Schema definition.\
> Useful for bootstrapping \`bodySchema\` in builder-mode APIs from real payload samples.\
> Input must be a non-empty JSON object -- arrays and primitives are rejected.\
> The generated schema is shallow (one level of \`properties\`); nested objects become\
> \`type: "object"\` without further property inference. Fill in or remove those nodes\
> before saving the result as a \`bodySchema\`: the API Builder editor can't render an\
> object node that has no properties.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/apis/schema":{"put":{"operationId":"convertJsonToSchema","tags":["APIs"],"summary":"Convert a JSON object to JSON Schema","description":"Accepts a sample JSON object and returns its inferred JSON Schema definition.\nUseful for bootstrapping `bodySchema` in builder-mode APIs from real payload samples.\nInput must be a non-empty JSON object -- arrays and primitives are rejected.\nThe generated schema is shallow (one level of `properties`); nested objects become\n`type: \"object\"` without further property inference. Fill in or remove those nodes\nbefore saving the result as a `bodySchema`: the API Builder editor can't render an\nobject node that has no properties.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Any sample JSON object to convert into JSON Schema."}}}},"responses":{"200":{"description":"JSON Schema generated successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string"},"properties":{"type":"object","additionalProperties":true}},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Update the grouping for one or more APIs

> Assigns or removes an API grouping for the specified API resources. Pass\
> \`\_apiGroupingId: null\` or omit it to ungroup. Nonexistent API IDs are silently accepted.\
> \
> Every API in \`\_apiIds\` must belong to the same integration, and the grouping must be\
> one of that integration's \`apiGroupings\`. Each API is re-saved through full validation,\
> so an API that cannot be saved as it stands (for example a builder API whose response\
> router is not configured yet) fails the request with 400 \`apigrouping\_update\_error\`;\
> regroup such an API with a full \`PUT /v1/apis/{\_id}\` instead.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/apis/updateApiGrouping":{"put":{"operationId":"updateApiGrouping","tags":["APIs"],"summary":"Update the grouping for one or more APIs","description":"Assigns or removes an API grouping for the specified API resources. Pass\n`_apiGroupingId: null` or omit it to ungroup. Nonexistent API IDs are silently accepted.\n\nEvery API in `_apiIds` must belong to the same integration, and the grouping must be\none of that integration's `apiGroupings`. Each API is re-saved through full validation,\nso an API that cannot be saved as it stands (for example a builder API whose response\nrouter is not configured yet) fails the request with 400 `apigrouping_update_error`;\nregroup such an API with a full `PUT /v1/apis/{_id}` instead.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["_apiIds"],"properties":{"_apiIds":{"type":"array","items":{"type":"string","format":"objectId"},"description":"List of API resource IDs to update."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"The grouping ID to assign. Pass `null` or omit to remove the\ncurrent grouping from the specified APIs."}}}}}},"responses":{"204":{"description":"API grouping updated successfully (no body returned)."},"400":{"description":"The request was rejected: the APIs span more than one integration\n(`invalid_request`), or one API could not be re-saved with the new grouping\n(`apigrouping_update_error` — the grouping belongs to another integration, or the\nAPI fails its own validation).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## List recent request/response logs for an API

> Returns the recent invocation traces captured for the named API. Each entry is a decoded\
> request/response pair — masked for credentials — that the runtime stored when the API was\
> called via its public endpoint. Use this to audit what the API has handled and to triage\
> errors without re-invoking the API.\
> \
> Traces are \*\*file-backed\*\* with server-controlled retention and capture scope; an empty\
> \`requests\[]\` simply means nothing is currently stored for this API. Two invocation sources do\
> \*\*not\*\* populate this log:\
> \- Test-runs via \`POST /v1/apis/{\_id}/test/run\` never surface here.\
> \- Script-mode API invocations via \`POST /v1/apis/{\_id}/request\` also do not surface here\
> &#x20; despite counting toward \`/v1/apis/usage\`. Only \*\*builder-mode\*\* invocations against the\
> &#x20; public endpoint (\`<https://api.integrator.io/apis/{version}{relativeURI}\\`>) populate logs.\
> \
> List entries are \*\*summaries\*\* (\`key\`, \`time\`, \`method\`, \`statusCode\`) — to see the decoded\
> request/response payload, follow up with \`GET /v1/apis/{\_id}/logs/{key}\`.\
> \
> \`statusCode\` is returned as a string in list entries but as an integer on the detail endpoint.\
> Credential values are masked as \`\*\*\*\*\*\*\*\*\` before storage and are not recoverable.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiLogsResponse":{"type":"object","description":"Request log envelope returned by `GET /v1/apis/{_id}/logs`. Contains the recent API invocation\ntraces for the API identified by `_id`. The `requests[]` array is empty when no invocations\nhave been logged — either the API has never been called, or debug capture is off, or the\nretention window has elapsed. Each entry is a full decoded request/response pair.","properties":{"requests":{"type":"array","description":"Invocation summaries, newest first. Each entry has just `{key, time, method, statusCode}`;\nthe decoded request/response payload lives behind `GET /v1/apis/{_id}/logs/{key}`.","items":{"$ref":"#/components/schemas/ApiLogEntry"}}}},"ApiLogEntry":{"type":"object","description":"Summary row returned in the `GET /v1/apis/{_id}/logs` listing. Carries just enough to identify\neach invocation (when it ran, how it ended) so the caller can pick which ones to inspect in\nfull via `GET /v1/apis/{_id}/logs/{key}`. Full request/response payloads are **not** in the\nlist — only in the detail fetch.","properties":{"key":{"type":"string","description":"Opaque log key. Pass to `GET /v1/apis/{_id}/logs/{key}` to retrieve the full decoded\ntransaction. Structure is `<seq>-<id>-<status>-<method>` (e.g.\n`5481201053696-a10af1ade8fe477a847771c1e3716e36-200-POST`). The embedded `<id>` also\nappears as `id` on the detail response."},"time":{"type":"integer","format":"int64","description":"Epoch milliseconds when the invocation was handled."},"method":{"type":"string","description":"HTTP method of the inbound request (`GET`, `POST`, ...)."},"statusCode":{"type":"string","description":"HTTP status code the API returned to the caller, as a **string** (e.g. `\"200\"`). Note: on\nthe detail endpoint this same value is exposed as an integer under `response.statusCode` —\nthe list surfaces it as a 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/apis/{_id}/logs":{"get":{"operationId":"listApiLogs","tags":["APIs"],"summary":"List recent request/response logs for an API","description":"Returns the recent invocation traces captured for the named API. Each entry is a decoded\nrequest/response pair — masked for credentials — that the runtime stored when the API was\ncalled via its public endpoint. Use this to audit what the API has handled and to triage\nerrors without re-invoking the API.\n\nTraces are **file-backed** with server-controlled retention and capture scope; an empty\n`requests[]` simply means nothing is currently stored for this API. Two invocation sources do\n**not** populate this log:\n- Test-runs via `POST /v1/apis/{_id}/test/run` never surface here.\n- Script-mode API invocations via `POST /v1/apis/{_id}/request` also do not surface here\n  despite counting toward `/v1/apis/usage`. Only **builder-mode** invocations against the\n  public endpoint (`https://api.integrator.io/apis/{version}{relativeURI}`) populate logs.\n\nList entries are **summaries** (`key`, `time`, `method`, `statusCode`) — to see the decoded\nrequest/response payload, follow up with `GET /v1/apis/{_id}/logs/{key}`.\n\n`statusCode` is returned as a string in list entries but as an integer on the detail endpoint.\nCredential values are masked as `********` before storage and are not recoverable.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Trace envelope. `requests[]` is empty when no invocations are currently stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiLogsResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get one request/response log entry by key

> Returns the full decoded request/response envelope for one API invocation, looked up by the\
> opaque \`key\` values surfaced in \`GET /v1/apis/{\_id}/logs\`. Matches the exact entry whose key is\
> provided — there is no partial-match or range query on this endpoint.\
> \
> Unlike the parent list (which only carries \`{key, time, method, statusCode}\`), this endpoint\
> returns the complete payload: request method/url/headers/body/queryParams/clientAddress,\
> response status/headers/body/responseTime, and (for builder-mode APIs) the\
> \`inputToResponseBubble\` snapshot of what the response-mapper saw. Sensitive header values\
> (\`authorization\`, OAuth bearer tokens) are masked as \`\*\*\*\*\*\*\*\*\` before storage.\
> \
> For builder APIs where the response mapper didn't produce the expected output, inspect\
> \`inputToResponseBubble.sourceRecord\` to see what the response stage actually received.\
> \`response.statusCode\` is an integer here but the sibling list endpoint returns it as a\
> string. A 404 \`file\_not\_found\` means the key has expired from retention or was never\
> captured.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiLogDetail":{"type":"object","description":"Full decoded request/response envelope for one API invocation, returned by\n`GET /v1/apis/{_id}/logs/{key}`. Sensitive header values (`authorization`, OAuth bearer tokens,\nand similar) are masked with `********` before storage — the originals are not recoverable.\nThe `inputToResponseBubble` block reveals the Celigo-internal state handed to the\nresponse-mapping stage; it's absent for script-mode APIs and pre-mapping failures.","properties":{"time":{"type":"integer","format":"int64","description":"Epoch milliseconds when the invocation was handled."},"request":{"type":"object","description":"The inbound HTTP request the API received, as decoded by the runtime.","properties":{"method":{"type":"string","description":"HTTP method of the inbound request."},"url":{"type":"string","description":"The path the caller hit, relative to `https://api.integrator.io`. Includes the API\n`{version}` and the API's configured `relativeURI` (e.g. `/apis/v1/hubspot`).\nQuery-string credentials are masked before storage."},"httpVersion":{"type":"string","description":"HTTP protocol version the caller negotiated (e.g. `1.1`, `2`)."},"headers":{"type":"object","description":"Inbound headers. The `authorization` header (and other credential headers) are masked.","additionalProperties":{"type":"string"}},"queryParams":{"type":"object","description":"Parsed query-string parameters. Empty object when none were sent.","additionalProperties":true},"body":{"type":"string","description":"Request body as received, verbatim string (JSON payloads arrive already serialized —\nparse with `JSON.parse` when you need structured data). Empty string for bodyless\nmethods."},"clientAddress":{"type":"string","description":"IP the request arrived from, as the Celigo edge saw it. IPv6 format; may be a\nprivate/loopback address (e.g. `::ffff:127.0.0.6`) when routed through an internal\nproxy rather than the public internet."},"size":{"type":"integer","description":"Byte size the runtime recorded for the request. Often `0` — this field is not consistently populated."}}},"response":{"type":"object","description":"The outbound HTTP response the API produced.","properties":{"statusCode":{"type":"integer","description":"HTTP status code returned to the caller, as an **integer** here. Note the list endpoint\n(`GET /v1/apis/{_id}/logs`) exposes the same value as a string."},"statusMessage":{"type":"string","description":"HTTP status reason phrase (`OK`, `Bad Request`, ...)."},"headers":{"type":"object","description":"Response headers sent to the caller.","additionalProperties":{"type":"string"}},"body":{"type":"string","description":"Response body as sent. String form; parse as JSON/XML per the `content-type` header."},"size":{"type":"integer","description":"Byte size of the serialized response body."},"responseTime":{"type":"integer","description":"Total time in milliseconds from request arrival to response flush."}}},"inputToResponseBubble":{"type":"object","description":"Builder-mode APIs only. Snapshot of the state handed to the response-mapping stage — the\nparsed input records plus any execution/configuration errors collected along the pipeline.\nUse this to debug response-mapping issues (\"what did the mapper actually see?\"). Absent on\nscript-mode APIs.","properties":{"sourceRecord":{"description":"Array of records (or single-record object) that the response-mapper was given as input."},"executionErrors":{"type":"array","description":"Runtime errors raised during processing (e.g. script exceptions, lookup failures).","items":{"type":"object","additionalProperties":true}},"configurationErrors":{"type":"array","description":"Configuration errors detected before execution (e.g. missing required mapping fields).","items":{"type":"object","additionalProperties":true}}}},"key":{"type":"string","description":"Echoes the `key` path parameter. Same structure as in the list (`<seq>-<id>-<status>-<method>`)."},"id":{"type":"string","description":"Shorter internal id for this log record. Appears embedded in the `key` string as the second\nsegment. Not independently useful to the caller, but handy for correlating with audit or\nmonitoring logs that reference only the short id."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/logs/{key}":{"get":{"operationId":"getApiLogByKey","tags":["APIs"],"summary":"Get one request/response log entry by key","description":"Returns the full decoded request/response envelope for one API invocation, looked up by the\nopaque `key` values surfaced in `GET /v1/apis/{_id}/logs`. Matches the exact entry whose key is\nprovided — there is no partial-match or range query on this endpoint.\n\nUnlike the parent list (which only carries `{key, time, method, statusCode}`), this endpoint\nreturns the complete payload: request method/url/headers/body/queryParams/clientAddress,\nresponse status/headers/body/responseTime, and (for builder-mode APIs) the\n`inputToResponseBubble` snapshot of what the response-mapper saw. Sensitive header values\n(`authorization`, OAuth bearer tokens) are masked as `********` before storage.\n\nFor builder APIs where the response mapper didn't produce the expected output, inspect\n`inputToResponseBubble.sourceRecord` to see what the response stage actually received.\n`response.statusCode` is an integer here but the sibling list endpoint returns it as a\nstring. A 404 `file_not_found` means the key has expired from retention or was never\ncaptured.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"key","in":"path","required":true,"description":"Opaque log key from the parent `GET /v1/apis/{_id}/logs` listing. Encodes status + method\n(e.g. `…-200-POST`) — use the `key` exactly as returned; do not construct one manually.","schema":{"type":"string"}}],"responses":{"200":{"description":"The decoded request/response envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiLogDetail"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## List API request run history (defaults to last 5 minutes)

> Returns the logged request executions of a builder-mode API — one entry per\
> inbound request to its public endpoint captured while the API's\
> \`logging.mode\` was anything other than \`noLogging\`, including requests that\
> failed before reaching a response step. Distinct from \`GET /v1/apis/{\_id}/logs\`,\
> which returns the legacy file-backed request/response envelopes: use\
> \`/requests\` for run history and trace drill-down, \`/logs\` for the raw decoded\
> request and response of a single call.\
> \
> Run history exists only for builder-mode APIs — a script-mode API id returns\
> 404 \`invalid\_ref\` ("api not found."), the same as an unknown id.\
> \
> Results are cursor-paginated (\`next\`/\`prev\`). When \`time\_gte\` / \`time\_lte\`\
> are omitted, only the last 5 minutes are returned — pass an explicit window\
> for a broader history. Use the \`executionId\` from a list entry with\
> \`GET /v1/apis/{\_id}/requests/{executionId}\` to open the trace view.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiRunHistoryResponse":{"type":"object","description":"Paginated API request run history.","required":["requests"],"properties":{"requests":{"type":"array","description":"Logged request executions, newest first by default.","items":{"$ref":"#/components/schemas/ApiRequestLogEntry"}},"nextPageUrl":{"type":["string","null"],"description":"URL to fetch the next page (carries the `next` cursor and\n`cursorExecutionId` tie-breaker); null when there is no next page."},"prevPageUrl":{"type":["string","null"],"description":"URL to fetch the previous page; null when there is no previous page."}}},"ApiRequestLogEntry":{"type":"object","description":"One logged API request execution in the run history.","required":["executionId","time","method","relativeURI","statusCode","timeTaken","logMode"],"properties":{"executionId":{"type":"string","description":"Identifier of this request execution (20-character lowercase hex).\nPass it to `GET /v1/apis/{_id}/requests/{executionId}` to open the\ntrace view, which every `logMode` records."},"time":{"type":"string","format":"date-time","description":"When the request was received (UTC)."},"method":{"type":"string","description":"HTTP method of the request."},"relativeURI":{"type":"string","description":"Path of the request without scheme or host, including the public\n`/apis/{version}` prefix ahead of the API's `relativeURI` and any\nquery string the caller sent."},"statusCode":{"type":"integer","description":"HTTP status code the API responded with."},"traceKey":{"type":"string","description":"Trace key computed from the API's `traceKeyTemplate` for this request.\nEmpty string when the API has no template."},"remoteIP":{"type":"string","description":"Client IP address the request came from."},"timeTaken":{"type":"number","description":"Processing time in milliseconds."},"logMode":{"type":"string","enum":["basic","standard","detailed","debug"],"description":"Logging mode that was active when this request was processed. Every\nmode records the trace view's step list; `detailed` and `debug` add the\nAPI's own request-parsing step. Requests processed while\n`logging.mode` is `noLogging` produce no run-history rows at all."}}},"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/apis/{_id}/requests":{"get":{"operationId":"listApiRequests","tags":["APIs"],"summary":"List API request run history (defaults to last 5 minutes)","description":"Returns the logged request executions of a builder-mode API — one entry per\ninbound request to its public endpoint captured while the API's\n`logging.mode` was anything other than `noLogging`, including requests that\nfailed before reaching a response step. Distinct from `GET /v1/apis/{_id}/logs`,\nwhich returns the legacy file-backed request/response envelopes: use\n`/requests` for run history and trace drill-down, `/logs` for the raw decoded\nrequest and response of a single call.\n\nRun history exists only for builder-mode APIs — a script-mode API id returns\n404 `invalid_ref` (\"api not found.\"), the same as an unknown id.\n\nResults are cursor-paginated (`next`/`prev`). When `time_gte` / `time_lte`\nare omitted, only the last 5 minutes are returned — pass an explicit window\nfor a broader history. Use the `executionId` from a list entry with\n`GET /v1/apis/{_id}/requests/{executionId}` to open the trace view.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"statusCode","in":"query","description":"Filter by HTTP response status code — a single value or a\ncomma-separated list. Every value must be an integer.","schema":{"type":"string","pattern":"^\\d+(,\\d+)*$"}},{"name":"method","in":"query","description":"Filter by HTTP method (case-insensitive; normalized to uppercase).","schema":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"]}},{"name":"traceKey","in":"query","description":"Prefix filter on the request trace key.","schema":{"type":"string"}},{"name":"remoteIP","in":"query","description":"Prefix filter on the client IP address.","schema":{"type":"string"}},{"name":"relativeURI","in":"query","description":"Prefix filter on the request relative URI.","schema":{"type":"string"}},{"name":"searchKey","in":"query","description":"Free-text search, OR-matched across `traceKey` (prefix), `remoteIP`\n(prefix), and `relativeURI` (substring). When provided, the individual\n`traceKey`/`remoteIP`/`relativeURI` filters are ignored. Values shorter\nthan 3 characters are rejected with 400.","schema":{"type":"string","minLength":3,"maxLength":500}},{"name":"pageSize","in":"query","description":"Number of entries per page. Values above the documented maximum are\nnot rejected — the server accepts them silently, so treat the\nmaximum as the supported contract rather than an enforced limit.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"sortOrder","in":"query","description":"Sort direction by request time.","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"next","in":"query","description":"ISO 8601 timestamp cursor for the next page (from `nextPageUrl`).\nMutually exclusive with `prev`; requires `cursorExecutionId`.","schema":{"type":"string","format":"date-time"}},{"name":"prev","in":"query","description":"ISO 8601 timestamp cursor for the previous page (from `prevPageUrl`).\nMutually exclusive with `next`; requires `cursorExecutionId`.","schema":{"type":"string","format":"date-time"}},{"name":"cursorExecutionId","in":"query","description":"Tie-breaker execution id, required when paging with `next`/`prev`.","schema":{"type":"string"}},{"name":"time_gte","in":"query","description":"Include requests at or after this ISO timestamp.","schema":{"type":"string","format":"date-time"}},{"name":"time_lte","in":"query","description":"Include requests at or before this ISO timestamp.","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Paginated run history. `requests[]` is empty when nothing matches.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiRunHistoryResponse"}}}},"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"}}}}}}
```

## Delete API request logs in a date range

> Queues asynchronous deletion of stored request log payloads for the API\
> within \`\[startedAt, endAt]\`. Returns \`202 Accepted\`; cleanup runs in the\
> background. Requires manage access for log deletion — monitor-level users\
> receive \`403\`.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"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"}}}}},"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/apis/{_id}/requests":{"delete":{"operationId":"deleteApiRequestLogs","tags":["APIs"],"summary":"Delete API request logs in a date range","description":"Queues asynchronous deletion of stored request log payloads for the API\nwithin `[startedAt, endAt]`. Returns `202 Accepted`; cleanup runs in the\nbackground. Requires manage access for log deletion — monitor-level users\nreceive `403`.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"startedAt","in":"query","required":true,"description":"Start of the deletion range, inclusive (ISO 8601). Must be before `endAt`.","schema":{"type":"string","format":"date-time"}},{"name":"endAt","in":"query","required":true,"description":"End of the deletion range, inclusive (ISO 8601). Must not be in the future.","schema":{"type":"string","format":"date-time"}}],"responses":{"202":{"description":"Deletion request accepted for asynchronous processing."},"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"}}}}}}
```

## Get trace metadata for an API request execution

> Returns the top-level execution steps for the trace view of one API\
> request, in execution order: the request-parsing step (identified by the\
> API's own id; omitted for requests logged in \`basic\` mode), one step per\
> export or import the request passed through, and the response step\
> (identified by the response \`id\`, such as \`success\`). A request that\
> failed mid-way lists only the steps that ran. Per-step payloads are\
> fetched separately with the log-data query endpoint.\
> \
> An unknown \`executionId\` returns \`200\` with an empty \`steps\` array; a\
> malformed one returns \`422\` (\`invalid\_execution\_id\`). An unknown or\
> script-mode API \`\_id\` returns \`404\`.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiTraceMetadataResponse":{"type":"object","description":"Top-level execution steps for the trace view of an API request.","required":["steps"],"properties":{"steps":{"type":"array","description":"Top-level execution steps for the trace view.","items":{"$ref":"#/components/schemas/ApiRequestTraceStep"}}}},"ApiRequestTraceStep":{"type":"object","description":"A step within an API request execution trace.","required":["status","timeTaken","groupId","recordId","time"],"properties":{"_expOrImpId":{"type":"string","description":"Identifies what ran: the API's own id for the request-parsing step, the\nexport or import id for a lookup or import step, the response `id`\n(for example `success`) for the response step, or `<toolId>_input` /\n`<toolId>_output` for the boundaries of a nested Tool step. A response\nstep whose `id` was named by the user can't be read through the\nlog-data query, which rejects that id with 400 `invalid_exp_or_imp_id`\nat every stage; read the step's outcome from this trace."},"status":{"type":"string","enum":["success","error","ignore"],"description":"Outcome status of the step."},"stage":{"type":"string","description":"Processing stage; present when `status` is `error` or `ignore`."},"timeTaken":{"type":"number","description":"Step processing time in milliseconds."},"groupId":{"type":"string","description":"Group identifier for the step's records."},"recordId":{"type":"string","description":"Identifier of this record."},"parentRecordId":{"type":"string","description":"Identifier of the parent record when this step is a child row; empty string on top-level steps."},"time":{"type":"string","format":"date-time","description":"Timestamp when the step ran (UTC)."}},"additionalProperties":true},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/requests/{executionId}":{"get":{"operationId":"getApiRequestTrace","tags":["APIs"],"summary":"Get trace metadata for an API request execution","description":"Returns the top-level execution steps for the trace view of one API\nrequest, in execution order: the request-parsing step (identified by the\nAPI's own id; omitted for requests logged in `basic` mode), one step per\nexport or import the request passed through, and the response step\n(identified by the response `id`, such as `success`). A request that\nfailed mid-way lists only the steps that ran. Per-step payloads are\nfetched separately with the log-data query endpoint.\n\nAn unknown `executionId` returns `200` with an empty `steps` array; a\nmalformed one returns `422` (`invalid_execution_id`). An unknown or\nscript-mode API `_id` returns `404`.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"executionId","in":"path","required":true,"description":"The execution id (20-character lowercase hex).","schema":{"type":"string","pattern":"^[0-9a-f]{20}$"}}],"responses":{"200":{"description":"Top-level trace steps for the request execution.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTraceMetadataResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List child records under an API trace step

> Returns the child records under a parent record within an API request\
> trace (lookup / one-to-many expansions). Results are cursor-paginated\
> (\`next\`/\`prev\`).

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiRequestChildrenResponse":{"type":"object","description":"Paginated child records under a parent record in an API request trace.","required":["children"],"properties":{"children":{"type":"array","description":"Child step records (lookup / one-to-many expansions).","items":{"$ref":"#/components/schemas/ApiRequestTraceStep"}},"nextPageUrl":{"type":["string","null"],"description":"URL to fetch the next page; null when there is no next page."},"prevPageUrl":{"type":["string","null"],"description":"URL to fetch the previous page; null when there is no previous page."}}},"ApiRequestTraceStep":{"type":"object","description":"A step within an API request execution trace.","required":["status","timeTaken","groupId","recordId","time"],"properties":{"_expOrImpId":{"type":"string","description":"Identifies what ran: the API's own id for the request-parsing step, the\nexport or import id for a lookup or import step, the response `id`\n(for example `success`) for the response step, or `<toolId>_input` /\n`<toolId>_output` for the boundaries of a nested Tool step. A response\nstep whose `id` was named by the user can't be read through the\nlog-data query, which rejects that id with 400 `invalid_exp_or_imp_id`\nat every stage; read the step's outcome from this trace."},"status":{"type":"string","enum":["success","error","ignore"],"description":"Outcome status of the step."},"stage":{"type":"string","description":"Processing stage; present when `status` is `error` or `ignore`."},"timeTaken":{"type":"number","description":"Step processing time in milliseconds."},"groupId":{"type":"string","description":"Group identifier for the step's records."},"recordId":{"type":"string","description":"Identifier of this record."},"parentRecordId":{"type":"string","description":"Identifier of the parent record when this step is a child row; empty string on top-level steps."},"time":{"type":"string","format":"date-time","description":"Timestamp when the step ran (UTC)."}},"additionalProperties":true},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/requests/{executionId}/{_expOrImpId}/logs/{parentRecordId}/children":{"get":{"operationId":"listApiRequestChildren","tags":["APIs"],"summary":"List child records under an API trace step","description":"Returns the child records under a parent record within an API request\ntrace (lookup / one-to-many expansions). Results are cursor-paginated\n(`next`/`prev`).","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"executionId","in":"path","required":true,"description":"The execution id (20-character lowercase hex).","schema":{"type":"string","pattern":"^[0-9a-f]{20}$"}},{"name":"_expOrImpId","in":"path","required":true,"description":"Export or import id of the step, or `<toolId>_input` / `<toolId>_output`\nfor a nested Tool step's boundary. Response-step ids such as `success`\nhave no child records and are rejected with 400.","schema":{"type":"string","pattern":"^[0-9a-fA-F]{24}(_(input|output))?$"}},{"name":"parentRecordId","in":"path","required":true,"description":"The parent record id whose children are returned.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter children by processing outcome — a single value or a\ncomma-separated list of `success`, `error`, `ignore`.","schema":{"type":"string","pattern":"^(success|error|ignore)(,(success|error|ignore))*$"}},{"name":"pageSize","in":"query","description":"Number of entries per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"sortOrder","in":"query","description":"Sort direction by step time.","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"next","in":"query","description":"ISO 8601 timestamp cursor for the next page (from `nextPageUrl`).\nMutually exclusive with `prev`; requires `cursorRecordId`.","schema":{"type":"string","format":"date-time"}},{"name":"prev","in":"query","description":"ISO 8601 timestamp cursor for the previous page (from `prevPageUrl`).\nMutually exclusive with `next`; requires `cursorRecordId`.","schema":{"type":"string","format":"date-time"}},{"name":"cursorRecordId","in":"query","description":"Tie-breaker record id, required when paging with `next`/`prev`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated child step records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiRequestChildrenResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Query decoded log data for an API trace step

> Returns the decoded request/response payload and error metadata for a\
> record/stage within an API request execution, identified by\
> \`\_expOrImpId\`, \`stage\`, \`groupId\`, and \`recordId\`. If the log content\
> exceeds inline limits or is stored externally, an \`externalReference\`\
> with an S3 key (and optional byte range) is returned — download it via\
> the signed-URL endpoint. The response may be gzip-compressed.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiLogDataRequest":{"type":"object","description":"Query payload for retrieving decoded log data for a step within an API\nrequest execution. Same shape as the flow log-data query.","required":["_expOrImpId","stage","groupId","recordId"],"properties":{"_expOrImpId":{"type":"string","description":"Step to read: the export or import id, an eleven-character builder\nresource-step identifier, or `<toolId>_input` / `<toolId>_output` for a\nnested Tool step's boundary. Any other value is rejected with 400\n`invalid_exp_or_imp_id`.","pattern":"^([0-9a-fA-F]{24}(_(input|output))?|[0-9A-Za-z]{11})$"},"stage":{"type":"string","description":"Processing stage to fetch data for."},"groupId":{"type":"string","description":"Group identifier for the step's records."},"recordId":{"type":"string","description":"Identifier of the record to fetch."}}},"ApiLogDataResponse":{"type":"object","description":"Decoded log payload for a step, plus any collected error metadata.","required":["logs","errors"],"properties":{"logs":{"type":"array","description":"Decoded log payload entries for the step. Large payloads are not inlined —\nsuch an entry carries an `externalReference[]`, each with a `source.s3Key`;\npass that key to `GET /v1/apis/{_id}/requests/{executionId}/logs/signedURL`\nto download the full content.","items":{"type":"object","properties":{"externalReference":{"type":"array","description":"References to externally stored payload content, present for large payloads.","items":{"type":"object","properties":{"source":{"type":"object","description":"Location of the externally stored content.","properties":{"s3Key":{"type":"string","description":"Relative key to pass to the signed-URL endpoint."}},"additionalProperties":true}},"additionalProperties":true}}},"additionalProperties":true}},"errors":{"type":"array","description":"Error metadata collected while resolving the payload.","items":{"type":"object","additionalProperties":true}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/requests/{executionId}/logs/data/query":{"post":{"operationId":"queryApiRequestLogData","tags":["APIs"],"summary":"Query decoded log data for an API trace step","description":"Returns the decoded request/response payload and error metadata for a\nrecord/stage within an API request execution, identified by\n`_expOrImpId`, `stage`, `groupId`, and `recordId`. If the log content\nexceeds inline limits or is stored externally, an `externalReference`\nwith an S3 key (and optional byte range) is returned — download it via\nthe signed-URL endpoint. The response may be gzip-compressed.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"executionId","in":"path","required":true,"description":"The execution id (20-character lowercase hex).","schema":{"type":"string","pattern":"^[0-9a-f]{20}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiLogDataRequest"}}}},"responses":{"200":{"description":"Log data (and/or external references) plus error metadata.","headers":{"Content-Encoding":{"description":"May be `gzip` to reduce transfer time for large responses.","schema":{"type":"string","enum":["gzip"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiLogDataResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get a signed URL for a stored API request log payload

> Returns a short-lived signed S3 URL (five-minute expiry) for the provided\
> \`s3Key\` suffix, taken from an \`externalReference\` returned by the log-data\
> query endpoint. The full S3 key is resolved under the execution's own log\
> prefix, so callers can only access logs for this API and execution; the\
> key is not checked for existence, so a mistyped suffix still yields a URL\
> that fails on download.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiSignedUrlResponse":{"type":"object","description":"A short-lived signed URL for downloading a stored API request log payload object.","required":["signedURL"],"properties":{"signedURL":{"type":"string","description":"Time-limited signed URL (five minutes) to download the referenced log object."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/requests/{executionId}/logs/signedURL":{"get":{"operationId":"getApiRequestLogSignedUrl","tags":["APIs"],"summary":"Get a signed URL for a stored API request log payload","description":"Returns a short-lived signed S3 URL (five-minute expiry) for the provided\n`s3Key` suffix, taken from an `externalReference` returned by the log-data\nquery endpoint. The full S3 key is resolved under the execution's own log\nprefix, so callers can only access logs for this API and execution; the\nkey is not checked for existence, so a mistyped suffix still yields a URL\nthat fails on download.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"executionId","in":"path","required":true,"description":"The execution id (20-character lowercase hex).","schema":{"type":"string","pattern":"^[0-9a-f]{20}$"}},{"name":"s3Key","in":"query","required":true,"description":"S3 object key suffix relative to the execution's log prefix, typically\nreturned in a prior log-data query `externalReference`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Signed URL for the requested object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSignedUrlResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List dependencies of an API

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

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"DependencyResponse":{"type":"object","description":"Map of dependent-resource types to arrays of dependency entries.\nKeys are plural resource type strings (e.g. `flows`, `imports`,\n`connections`). An empty object `{}` means no dependents.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/DependencyEntry"}}},"DependencyEntry":{"type":"object","description":"A single resource that depends on the queried resource.","properties":{"id":{"type":"string","description":"Unique identifier of the dependent resource."},"name":{"type":"string","description":"Display name of the dependent resource."},"type":{"type":"string","description":"Sub-type of the dependent resource when its collection distinguishes one, such as\n`stream` for a listener export. Only present for resource types that carry a `type`."},"paths":{"type":"array","description":"Dot-notation paths within the dependent resource that reference\nthe target resource. `[*]` denotes array elements.","items":{"type":"string"}},"accessLevel":{"type":"string","description":"The caller's access level on the dependent resource."},"dependencyIds":{"type":"object","description":"Map of resource types to arrays of IDs that this dependent\nresource references on the target. Keys are singular or plural\nresource type strings; values are arrays of ID strings.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["id","name","paths","accessLevel","dependencyIds"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/apis/{_id}/dependencies":{"get":{"operationId":"listApiDependencies","tags":["APIs"],"summary":"List dependencies of an API","description":"Returns the set of resources that depend on the specified resource.\nThe response is an object whose keys are dependent-resource types\n(e.g. `flows`, `imports`) and whose values are arrays of dependency\nentries. An empty object `{}` means no other resources depend on the\ntarget -- this is also returned for a well-formatted but nonexistent id.","parameters":[{"name":"_id","in":"path","required":true,"description":"Resource ID.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Dependency map. Keys are resource-type strings; values are arrays\nof dependency entries. Returns `{}` when no dependents exist.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DependencyResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## List connections an API depends on

> Returns the connections referenced by the export and import steps in \`builder.routers\`,\
> including connections a nested Tool step supplies through its overrides. Each connection\
> appears once even when several steps share it. Use this to see which systems an API talks\
> to before cloning it or calling \`PUT /v1/apis/{\_id}/replaceConnection\`.\
> \
> Callers with manage access to the API's integration receive full Connection objects;\
> callers with monitor-only access receive a reduced representation (\`\_id\`, \`name\`,\
> \`description\`, \`type\`, and the connector or database type under the adaptor key) without\
> endpoint or credential fields. Script-mode APIs have no steps and return an empty array.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"Connection":{"type":"object","required":["_id","name","type","createdAt","lastModified"],"description":"Connection object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ResponseBase"},{"type":"object","properties":{"netsuite":{"description":"Present when `type` is `netsuite`.","allOf":[{"$ref":"#/components/schemas/NetSuite"},{"type":"object","properties":{"suiteAppInstalled":{"type":"boolean","readOnly":true,"description":"When true, the Celigo integrator.io SuiteApp (SuiteScript 2.x) was detected in\nthe connected NetSuite account the last time the connection authenticated. It\nsays nothing about the legacy Celigo bundle; for a live check of both, use\n`GET /v1/connections/{_id}/distributedApps`."}}}]},"salesforce":{"description":"Present when `type` is `salesforce`.","allOf":[{"$ref":"#/components/schemas/Salesforce"},{"type":"object","properties":{"info":{"type":"object","readOnly":true,"description":"Salesforce org and user metadata populated by the server after a successful\nauthentication (the OpenID Connect userinfo of the authorizing user). Read-only.","properties":{"user_id":{"type":"string","readOnly":true,"description":"Salesforce user ID of the authorizing user."},"organization_id":{"type":"string","readOnly":true,"description":"Salesforce organization (org) ID this connection authenticates to."},"email":{"type":"string","format":"email","readOnly":true,"description":"Email address of the authorizing Salesforce user."},"preferred_username":{"type":"string","readOnly":true,"description":"Salesforce login username of the authorizing user."},"name":{"type":"string","readOnly":true,"description":"Full display name of the authorizing user."},"is_salesforce_integration_user":{"type":"boolean","readOnly":true,"description":"When true, the authorizing user is a Salesforce Integration User license."}}}}}]},"ftp":{"description":"Present when `type` is `ftp`.","allOf":[{"$ref":"#/components/schemas/FTP"}]},"s3":{"description":"Present when `type` is `s3`.","allOf":[{"$ref":"#/components/schemas/S3"}]},"http":{"description":"Present when `type` is `http`.","allOf":[{"$ref":"#/components/schemas/HTTP"}]},"rdbms":{"description":"Present when `type` is `rdbms`.","allOf":[{"$ref":"#/components/schemas/RDBMS"}]},"mongodb":{"description":"Present when `type` is `mongodb`.","allOf":[{"$ref":"#/components/schemas/MongoDB"}]},"as2":{"description":"Present when `type` is `as2`.","allOf":[{"$ref":"#/components/schemas/AS2"}]},"filesystem":{"description":"Present when `type` is `filesystem`.","allOf":[{"$ref":"#/components/schemas/Filesystem"}]},"mcp":{"description":"Present when `type` is `mcp`.","allOf":[{"$ref":"#/components/schemas/MCP"}]},"dynamodb":{"description":"Present when `type` is `dynamodb`.","allOf":[{"$ref":"#/components/schemas/DynamoDB"}]},"jdbc":{"description":"Present when `type` is `jdbc`.","allOf":[{"$ref":"#/components/schemas/JDBC"}]},"van":{"description":"Present when `type` is `van`.","allOf":[{"$ref":"#/components/schemas/VAN"}]},"wrapper":{"description":"Present when `type` is `wrapper`.","allOf":[{"$ref":"#/components/schemas/Wrapper"}]}}}],"if":{"properties":{"type":{"const":"netsuite"}},"required":["type"]},"then":{"required":["netsuite"]},"else":{"if":{"properties":{"type":{"const":"salesforce"}},"required":["type"]},"then":{"required":["salesforce"]},"else":{"if":{"properties":{"type":{"const":"ftp"}},"required":["type"]},"then":{"required":["ftp"]},"else":{"if":{"properties":{"type":{"const":"s3"}},"required":["type"]},"then":{"required":["s3"]},"else":{"if":{"properties":{"type":{"const":"http"}},"required":["type"]},"then":{"required":["http"]},"else":{"if":{"properties":{"type":{"const":"rdbms"}},"required":["type"]},"then":{"required":["rdbms"]},"else":{"if":{"properties":{"type":{"const":"mongodb"}},"required":["type"]},"then":{"required":["mongodb"]},"else":{"if":{"properties":{"type":{"const":"as2"}},"required":["type"]},"then":{"required":["as2"]},"else":{"if":{"properties":{"type":{"const":"filesystem"}},"required":["type"]},"then":{"required":["filesystem"]},"else":{"if":{"properties":{"type":{"const":"mcp"}},"required":["type"]},"then":{"required":["mcp"]},"else":{"if":{"properties":{"type":{"const":"dynamodb"}},"required":["type"]},"then":{"required":["dynamodb"]},"else":{"if":{"properties":{"type":{"const":"jdbc"}},"required":["type"]},"then":{"required":["jdbc"]},"else":{"if":{"properties":{"type":{"const":"van"}},"required":["type"]},"then":{"required":["van"]},"else":{"if":{"properties":{"type":{"const":"wrapper"}},"required":["type"]},"then":{"required":["wrapper"]},"else":{"if":{"properties":{"type":{"const":"rest"}},"required":["type"]},"then":{"required":["rest"]}}}}}}}}}}}}}}}},"ResponseBase":{"type":"object","description":"Shared properties present on every connection response regardless of type.","allOf":[{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"name":{"type":"string","description":"Display name for the connection.","maxLength":100},"type":{"type":"string","description":"The type of connection determining which authentication and connectivity options are available","enum":["netsuite","salesforce","ftp","s3","wrapper","http","rdbms","mongodb","as2","filesystem","mcp","dynamodb","jdbc","van","rest"]},"externalId":{"type":"string","description":"External identifier for the connection, often used for integration with third-party systems"},"assistant":{"type":"string","description":"Application name in lowercase for HTTP connections to systems with integrator.io adaptors.\nUsed to identify the target application being connected to.\nExamples - Shopify: \"shopify\", eBay: \"ebay\".\nOnly applicable for HTTP connection types.\n"},"_agentId":{"type":"string","format":"objectId","description":"Reference to a Celigo on-premise Agent. Required for connection types that need\nlocal network or filesystem access (JDBC, filesystem, Oracle RDBMS, and on-premise MongoDB).\nThe agent establishes a secure tunnel between the on-premise environment and integrator.io.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","format":"objectId","description":"Reference to another connection to share concurrency limits with. When set, this\nconnection's traffic counts against the referenced connection's limit instead of its own,\nand its own concurrency and auto-recovery settings have no effect. One level only: the\nreferenced connection may not itself borrow, and a connection that others borrow from\ncannot start borrowing. A connection cannot reference itself (422)."},"debugDate":{"type":"string","format":"date-time","description":"Date until which debug logging is enabled for this connection"},"settingsForm":{"type":"object","description":"Dynamic form configuration for connection-specific settings"},"settings":{"type":"object","description":"Connection-specific settings and configurations"},"pgp":{"description":"Present for file-based connections (ftp, s3, filesystem, …) that encrypt or decrypt files with PGP.","allOf":[{"$ref":"#/components/schemas/PGP"}]},"ssl":{"$ref":"#/components/schemas/SSL"},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"offline":{"type":"boolean","description":"When true, the connection has been taken offline and is skipped during flow execution.\nIt is set by the connection test a create or `PUT` runs: the result arrives in the\nwrite's response or, when the target is slow to answer, shortly afterwards (the audit\nlog records a `system` change; `lastModified` doesn't move), so read it again a few\nseconds after the write. On an `http` connection the write runs the test only when\n`http.ping` is configured, and an `http` connection that was never tested has no\n`offline` key.","readOnly":true},"needsAuthorization":{"type":"boolean","readOnly":true,"description":"OAuth handshake state. Celigo's OAuth callback sets it to `false` once the user consents\nand the tokens are stored (see `GET /v1/connection/{_id}/oauth2`). A connection that\nwas never authorized usually has no `needsAuthorization` key, so its absence does not\nmean the connection is authorized."},"_sourceId":{"type":"string","format":"objectId","description":"Source connection this was cloned from.","readOnly":true},"connectionRole":{"type":"string","enum":["standard","mcpChild"],"readOnly":true,"description":"Distinguishes account-owned connections from the per-end-user credential copies\nMCP servers collect. Absent on connections last saved before the field existed,\nwhich behave as `standard`. Sending `mcpChild` on `POST` or `PUT /v1/connections`\nfails with 422 `mcp_child_generic_route_not_allowed`, and `/connectionRole` is not a\npatchable path; child connections are written only by the MCP end-user setup page,\nnever through `/v1`."},"endUserProvidedFields":{"type":"array","items":{"type":"string"},"description":"Dot-paths of this connection's fields (for example `http.encrypted.apiKey` or\n`rdbms.user`) that each MCP end user must supply on their own `mcpChild` copy instead\nof inheriting the parent's value. Only returned on a `standard` connection that has\npaths set; never returned on a child. Writable through `POST`, `PUT`, and `PATCH`;\nby the platform contract, a write that changes the list invalidates the children end\nusers already hold against this parent."},"_parentConnectionId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent connection this child copies its non-credential configuration from. Present\nonly when `connectionRole` is `mcpChild`; set by the end-user setup page and ignored\nwhen sent on a standard connection."},"_mcpOwnerId":{"type":"string","format":"objectId","readOnly":true,"description":"Account owner whose parent connection and MCP servers this child belongs to. Present\nonly when `connectionRole` is `mcpChild`; on a child, `_userId` is the end user and\nthis field is the account."},"_parentSyncedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the child's non-credential fields were last synced from the parent\nconnection. Present only when `connectionRole` is `mcpChild`."},"_userId":{"type":"string","format":"objectId","description":"End user who owns this `mcpChild` connection's credentials. Present only when\n`connectionRole` is `mcpChild`; a standard connection belongs to the account and\nomits this field.","readOnly":true},"debugUntil":{"type":"string","format":"date-time","description":"Debug logging is active until this timestamp. Absent or in the past means debug is off.","readOnly":true},"encrypted":{"type":"string","description":"Masked placeholder for encrypted credential fields. Always returns `\"******\"`.","readOnly":true},"isHTTP":{"type":"boolean","description":"When true, the connection uses the HTTP adaptor internally, even when `type` is `wrapper`.","readOnly":true},"autoRecoverRateLimitErrors":{"type":"boolean","default":true,"description":"When true, rate-limit errors from the target system trigger automatic recovery: concurrency\ndrops to 1, the rate-limited requests are retried with doubling waits (1 to 1024 minutes,\nafter which the flag switches itself off), and concurrency climbs back toward\n`targetConcurrencyLevel`. While true, `targetConcurrencyLevel` is the throughput lever: a\n`concurrencyLevel` sent in a PUT is ignored, and one sent in a PATCH is stored but the\nrecovery machinery moves it back toward the target. Recovery never runs on `ftp`\nconnections: FTP errors aren't treated as rate limits."},"enableMicroBatchForOneToMany":{"type":"boolean","default":true,"description":"When true, enables micro-batching for one-to-many data flows through this connection."},"enableCsvObjectParsing":{"type":"boolean","default":true,"description":"When true, enables CSV-to-object parsing for data received through this connection."},"microServices":{"type":"object","description":"Per-adaptor feature flags controlling which microservice workers handle this connection's traffic.","readOnly":true,"properties":{"disableHttp":{"type":"boolean","description":"When true, the HTTP microservice worker is disabled for this connection."},"disableNetSuiteDistributed":{"type":"boolean","description":"When true, the NetSuite distributed-processing worker is disabled for this connection."},"disableNetSuiteProxy":{"type":"boolean","description":"When true, the NetSuite proxy worker is disabled for this connection."},"disableNetSuiteWebservices":{"type":"boolean","description":"When true, the NetSuite SuiteTalk Web Services worker is disabled for this connection."},"disableRdbms":{"type":"boolean","description":"When true, the RDBMS worker is disabled for this connection."},"disableAs2":{"type":"boolean","description":"When true, the AS2 worker is disabled for this connection."},"disableAs2File":{"type":"boolean","description":"When true, the AS2 file-processing worker is disabled for this connection."},"disableDataLoaderFile":{"type":"boolean","description":"When true, the data-loader file worker is disabled for this connection."},"disableFtp":{"type":"boolean","description":"When true, the FTP worker is disabled for this connection."},"disableS3":{"type":"boolean","description":"When true, the S3 worker is disabled for this connection."},"disableSalesforce":{"type":"boolean","description":"When true, the Salesforce worker is disabled for this connection."},"disableFile":{"type":"boolean","description":"When true, the generic file worker is disabled for this connection."},"disableNsFile":{"type":"boolean","description":"When true, the NetSuite file worker is disabled for this connection."},"workerGroup":{"type":"string","description":"Name of the worker group that processes this connection's traffic."}}},"queues":{"type":"array","description":"Message queue sizes for this connection. Always present on GET-by-ID; on the list endpoint only when `fetchQueueSize=true`.","readOnly":true,"items":{"type":"object","properties":{"name":{"type":"string","description":"Queue identifier (typically the connection ID)."},"size":{"type":"integer","description":"Number of messages currently in the queue."}}}}}}]},"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"]},"IAResourceResponse":{"type":"object","description":"Integration app response fields for resources that are part of integration apps","properties":{"_integrationId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the specific integration instance that contains this resource.\n\nThis field is only populated for resources that are part of an integration app\ninstallation. It contains the unique identifier (_id) of the integration\nresource that was installed in the account.\n\nThe integration instance represents a specific installed instance of an\nintegration app, with its own configuration, settings, and runtime environment.\n\nThis reference enables:\n- Tracing the resource back to its parent integration instance\n- Permission and access control based on integration ownership\n- Lifecycle management (enabling/disabling, updating, or uninstalling)\n"},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App (connector) that defines this resource. Present only on resources an\nIntegration App owns. The app locks parts of these documents, and a PUT that changes a\nlocked field answers 200 but keeps the stored value, so read the document back to confirm\na change."}}},"PGP":{"type":"object","description":"PGP encryption settings for file-based connections (ftp, s3, and similar). When set, files are\nPGP-encrypted before upload and/or decrypted after download. Supply at least one of `publicKey`\n(to encrypt outbound files) or `privateKey` (to decrypt inbound files); set `passphrase` whenever\n`privateKey` is provided.","properties":{"publicKey":{"type":"string","description":"ASCII-armored PGP public key used to encrypt outbound files before upload.\nSet this when the connection sends encrypted files; omit it for decrypt-only connections."},"privateKey":{"type":"string","writeOnly":true,"description":"ASCII-armored PGP private key used to decrypt inbound files after download (encrypted at rest;\nreturned masked as `\"******\"`). Set this when the connection receives encrypted files."},"passphrase":{"type":"string","writeOnly":true,"description":"Passphrase that unlocks `privateKey` (encrypted at rest; returned masked as `\"******\"`). Set this whenever `privateKey` is provided."},"compressionAlgorithm":{"type":"string","enum":["zip","zlib"],"description":"Compression applied to the message payload before PGP encryption. Match the algorithm the recipient expects; leave unset to use the server default."},"asciiArmored":{"type":"boolean","default":true,"description":"When true, produces ASCII-armored (text) PGP output. Set to false only when the recipient requires binary PGP output."}},"if":{"required":["privateKey"]},"then":{"required":["passphrase"]}},"SSL":{"type":"object","description":"SSL/TLS certificate configuration for database connections that use client certificate\n(mTLS) authentication or connect to servers with private CA-signed certificates. Provide\ncert and key together for mTLS, ca for a private CA, and passphrase only when the private\nkey is encrypted; cert/key and ca can be combined.","properties":{"ca":{"type":"string","description":"Certificate Authority certificate in PEM format. Set when the database server uses a\ncertificate signed by a private CA not in the system's default trust store.","writeOnly":true},"key":{"type":"string","description":"Client private key in PEM format, paired with cert for mTLS authentication.\nCannot be provided without cert.","writeOnly":true},"passphrase":{"type":"string","description":"Passphrase that decrypts the private key in the key field, when that key is password-protected.","writeOnly":true},"cert":{"type":"string","description":"Client certificate in PEM format, paired with key for mTLS authentication.\nCannot be provided without key.","writeOnly":true}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"NetSuite":{"type":"object","description":"Configuration for NetSuite ERP connections. Used when the connection type is \"netsuite\".\nThe authType field selects the authentication method; token-based authentication (TBA) is\nrecommended for production.","required":["authType"],"properties":{"authType":{"type":"string","enum":["token","token-auto"],"description":"Authentication method for the NetSuite connection. token-auto delegates the token\nlifecycle to an iClient; token uses a manually-supplied tokenId/tokenSecret pair."},"account":{"type":"string","description":"NetSuite account ID (automatically uppercased), required for token and token-auto authentication.\nFound in NetSuite under Setup > Company > Company Information. Non-production accounts\ncarry an environment suffix (e.g. `123456_SB1`); production and beta use the bare id."},"environment":{"type":"string","enum":["production","sandbox","sandbox2.0","beta"],"description":"NetSuite environment to connect to. Defaults to production when not specified."},"tokenId":{"type":"string","description":"NetSuite TBA token ID (encrypted at rest). Required when authType is \"token\".\n\nGenerated in NetSuite under Setup > Users/Roles > Access Tokens.\nMust be paired with the corresponding tokenSecret.\n","writeOnly":true},"tokenSecret":{"type":"string","description":"NetSuite TBA token secret (encrypted at rest). Required when authType is \"token\".\n\nGenerated alongside the tokenId in NetSuite. Treat as a sensitive credential.\n","writeOnly":true},"entityId":{"type":"string","description":"NetSuite entity/user ID associated with the token."},"tokenName":{"type":"string","description":"Human-readable name of the NetSuite access token for identification purposes."},"roleId":{"type":"string","description":"NetSuite role ID that determines the permissions for this connection.\n\nThe role controls which records, fields, and operations are accessible.\nMust match the role associated with the access token in NetSuite.\n"},"requestLevelCredentials":{"type":"boolean","default":false,"description":"When true, authentication credentials are sent with each individual API request\nrather than maintaining a persistent session. The connection form sets this to true\nfor token (manual TBA) authentication.\n"},"dataCenterURLs":{"type":"object","description":"NetSuite data center URLs for the account, auto-discovered from the account ID.\nThese are populated by the server after a successful connection.\n","readOnly":true,"properties":{"restDomain":{"type":"string","description":"Base URL for the account's RESTlet and REST API endpoints."},"webservicesDomain":{"type":"string","description":"Base URL for the account's SuiteTalk (SOAP) web services endpoints."},"systemDomain":{"type":"string","description":"Base URL for the account's NetSuite UI/system endpoints."}}},"accountName":{"type":"string","description":"Human-readable NetSuite account name (display purposes only)."},"roleName":{"type":"string","description":"Human-readable name of the NetSuite role (display purposes only)."},"wsdlVersion":{"type":"string","description":"SuiteTalk Web Services WSDL version. The API stores only `latest` or `next`; any other value sent\non create or update is normalized to one of these (the connection form's \"2025.1\" maps to `latest`\nand \"2023.1\" maps to `next`; unrecognized version strings fall back to `latest`). Defaults to\n`latest`, which requires Token-Based Authentication.","enum":["latest","next"],"default":"latest"},"applicationId":{"type":"string","description":"NetSuite application ID from the integration record.\nRequired for some authentication configurations to identify the calling application.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of requests this connection sends to NetSuite in parallel, across SOAP,\nREST and RESTlet calls. Send no more than the integrator.io license ceiling (25 standard,\n50 with an Environments license). NetSuite separately enforces one\nconcurrency limit per NetSuite account that every caller of its SOAP, REST and RESTlet\nAPIs shares — all integrator.io connections to that account and every other client\ncalling those APIs from outside integrator.io (other integrations, third-party tools).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on rate limit and governance feedback.","minimum":1,"maximum":50,"default":5},"_iClientId":{"type":"string","format":"objectId","description":"ID of the iClient used for token-based authentication."}}},"Salesforce":{"type":"object","description":"Configuration for Salesforce CRM connections. Used when the connection type is \"salesforce\".\nAuthenticates via OAuth 2.0: oauth2FlowType \"jwtBearerToken\" does server-to-server auth\nthrough a Connected App (recommended for automation), while \"refreshToken\" uses an\ninteractive browser authorization for user-context integrations.","required":["oauth2FlowType","sandbox"],"properties":{"sandbox":{"type":"boolean","description":"Whether this connection targets a Salesforce non-production (sandbox) org. When true,\nauthenticates against test.salesforce.com instead of login.salesforce.com. Must match\nthe actual Salesforce org type or authentication fails. This is the form's\nproduction-vs-sandbox selector (distinct from the connection-level `sandbox` flag).","default":false},"oauth2FlowType":{"type":"string","enum":["jwtBearerToken","refreshToken"],"description":"OAuth 2.0 authentication flow type. Use jwtBearerToken for automated server-to-server\nintegrations (requires a Connected App with a digital certificate and the username field).\nUse refreshToken for integrations that operate in a specific user's context. Defaults to\nrefreshToken when omitted.","default":"refreshToken"},"username":{"type":"string","description":"Salesforce login username (email) of the user whose permissions the integration operates\nunder. Used by the jwtBearerToken flow to identify the subject of the assertion."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to the iClient holding your own Salesforce Connected App's client ID and secret.\nSet this to authenticate through a custom Connected App; omit it to use Celigo's\npre-configured Connected App."},"baseURI":{"type":"string","format":"uri","description":"Salesforce instance URL for this org (e.g. \"https://mycompany.my.salesforce.com\").\nAuto-discovered and populated during OAuth authentication; set it explicitly only to\nforce a specific instance URL."},"bearerToken":{"type":"string","writeOnly":true,"description":"OAuth access token for Salesforce API calls (encrypted at rest; returned masked as\n`\"******\"`). Auto-managed by the system during the OAuth flow; rarely set manually."},"refreshToken":{"type":"string","writeOnly":true,"description":"OAuth refresh token used to mint new access tokens (encrypted at rest; returned masked as\n`\"******\"`). Obtained during the initial browser-based authorization of the refreshToken\nflow; auto-managed by the system."},"packagedOAuth":{"type":"boolean","description":"When true, the connection uses Celigo's pre-configured (packaged) Connected App. Set by\nthe system based on whether a custom `_iClientId` is supplied and the OAuth flow completed;\nnot reliably honored when supplied in the request body."},"scope":{"type":"array","items":{"type":"string"},"description":"OAuth scopes requested during authorization. Scope values are defined by Salesforce — `full`\ngrants complete API access and `refresh_token` enables long-lived refresh tokens. Defaults\nto `full` and `refresh_token` when omitted. A saved empty array is the normal stored state:\nthe connection form does not expose this field, and every save from the connection editor\nresets values written through the API.","default":["full","refresh_token"]},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent API requests to Salesforce. Salesforce enforces per-org API\nrequest limits, so setting this high consumes the org's API call allocation faster. Send no\nmore than the account's licensed ceiling.","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaling concurrency. When automatic rate-limit recovery is enabled, the\nsystem adjusts concurrency between 1 and this value based on rate-limit feedback from\nSalesforce. Send no more than the account's licensed ceiling.","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"oauth2FlowType":{"const":"jwtBearerToken"}},"required":["oauth2FlowType"]},"then":{"required":["username"]}},"FTP":{"type":"object","description":"Configuration for FTP/SFTP/FTPS file transfer connections. Used when the connection type is \"ftp\".\nThe type field selects the transfer protocol, which determines port defaults and available auth methods.","required":["type","hostURI","username"],"properties":{"type":{"type":"string","enum":["ftp","sftp","ftps"],"description":"File transfer protocol type. Prefer sftp for security. Use ftps when the\nserver requires TLS. Only use ftp for legacy systems without encryption support."},"hostURI":{"type":"string","description":"FTP server hostname or IP address.\nDo NOT include the protocol prefix (e.g., use \"ftp.example.com\", not \"sftp://ftp.example.com\").\n"},"port":{"type":"number","description":"Server port number. When omitted, defaults to the standard port for the\nprotocol: 21 for ftp, 22 for sftp, 21 for explicit ftps, and 990 for implicit ftps.\n","minimum":0,"maximum":65535},"username":{"type":"string","description":"Username for server authentication."},"password":{"type":"string","writeOnly":true,"description":"Password for server authentication (encrypted at rest; returned masked as `\"******\"`).\nFor sftp, supply either password or authKey (SSH key)."},"authKey":{"type":"string","description":"SSH private key for SFTP key-based authentication (encrypted at rest; returned masked as `\"******\"`).\nOnly used when type is \"sftp\"; can be used alone or alongside a password. Must be an RSA (SSH-2) key\nin PEM format, supplied whole from its BEGIN line to its END line — OpenSSH-format keys (a first\nline that names an OPENSSH PRIVATE KEY), passphrase-protected keys, SSH-1 keys and PuTTY `.ppk` files\nare not supported and must be converted to an unencrypted PEM key first.","writeOnly":true},"usePassiveMode":{"type":"boolean","description":"When true, uses passive mode for FTP/FTPS data connections.\nIn passive mode, the client initiates both control and data connections,\nwhich works better through firewalls and NAT. Enable for most scenarios.\n","default":true},"enableHostVerification":{"type":"boolean","description":"When true, verifies the server's SSH host key (sftp) or TLS certificate (ftps).\nDisable only for development/testing with self-signed certificates.\n"},"userDirectoryIsRoot":{"type":"boolean","description":"When true, treats the user's home directory as the root directory.\nAll paths are relative to the user's home directory rather than the server root.\n","default":false},"useImplicitFtps":{"type":"boolean","description":"When true, uses implicit FTPS (TLS connection established immediately on port 990).\nWhen false, uses explicit FTPS (starts as FTP on port 21, upgrades to TLS via STARTTLS).\nOnly applies when type is \"ftps\".\n","default":false},"requireSocketReUse":{"type":"boolean","description":"When true, requires the data connection to reuse the same TLS session as the control connection.\nSome FTPS servers require this for security. Only applies to FTPS connections.\n","default":false},"entryParser":{"type":"string","enum":["UNIX","UNIX-TRIM","VMS","WINDOWS","OS/2","OS/400","AS/400","MVS","UNKNOWN-TYPE","NETWARE","MACOS-PETER"],"description":"File listing format parser. Controls how directory listings from the server are interpreted.\nMost servers use UNIX format. Only change this if directory listings appear garbled."},"tradingPartner":{"type":"boolean","readOnly":true,"description":"When true, this connection is designated a B2B/EDI trading partner. Read-only on the connection\nbody — POST/PUT of this field are silently ignored; it is toggled via\n`PUT /connections/{_id}/tradingPartner` (used by the EDI B2B Manager).\n"},"_tpConnectorId":{"type":"string","format":"objectId","description":"Reference to the trading partner connector this connection belongs to. Must reference an\nexisting, published trading partner connector; the API rejects an unknown or unpublished ID\nwith 422 `tpconnector_not_found`.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent file transfer operations.\nFTP servers often have low connection limits — keep this value conservative.\nSend no more than the account's licensed maximum, the license's `concurrency` (25 standard,\n50 with an Environments license).\nWhile `autoRecoverRateLimitErrors` is true, which a create gets unless it sends `false`, a create\nignores the value sent here and sets this field to `targetConcurrencyLevel`, or to 1 when no\ntarget is sent. To start higher, send `targetConcurrencyLevel` too, or create with\n`autoRecoverRateLimitErrors: false`.\nUnlike the rest of the `ftp` object, a `PUT` that omits this field keeps the stored value instead of clearing it.\n","minimum":1,"maximum":50,"default":1},"targetConcurrencyLevel":{"type":"integer","description":"While `autoRecoverRateLimitErrors` is true, a create sets `concurrencyLevel` to this value, and a\ncreate that omits it gets 1 for both. Auto-recovery never runs on FTP connections (FTP errors\naren't treated as rate limits), so nothing climbs back to it.\nKept on a `PUT` that omits it, like `concurrencyLevel`; unset by the save while\n`autoRecoverRateLimitErrors` is false.\n","minimum":1,"maximum":50},"multiThreadCount":{"type":"integer","minimum":1,"description":"Number of parallel transfer threads for this FTP connection. Must be a\nwhole number — decimals are rejected on save. Send no more than the\naccount's licensed concurrency maximum, the same as for `concurrencyLevel`. On\nsave the value is mirrored into `userConcurrencyLevel` (and into\n`userTargetConcurrencyLevel` when auto-recovery of rate-limit errors\nis active with `targetConcurrencyLevel` set); clearing it clears the\nmirrors. Not preserved across a `PUT` — re-send it with the rest of\nthe `ftp` object or it is cleared."},"userConcurrencyLevel":{"type":"integer","readOnly":true,"description":"Server-maintained mirror of `multiThreadCount`. Present when\n`multiThreadCount` is set; do not send it — it is recomputed on save."},"userTargetConcurrencyLevel":{"type":"integer","readOnly":true,"description":"Server-maintained mirror of `multiThreadCount`, present while\n`autoRecoverRateLimitErrors` is true and `targetConcurrencyLevel` is\nset; recomputed on save."}},"if":{"properties":{"type":{"const":"sftp"}},"required":["type"]},"then":{"anyOf":[{"required":["password"]},{"required":["authKey"]}]},"else":{"required":["password"]}},"S3":{"type":"object","description":"Configuration for Amazon S3 connections. Used when the connection type is \"s3\". Provides\nupload, download, list, and delete access to S3 buckets. Authenticate with a static IAM\naccess key pair (authType `accesskey`) or by referencing an iClient that holds AWS IAM role\ncredentials (authType `awsIam`). Set pingBucket to an accessible bucket so Celigo can validate\nthe credentials.","properties":{"authType":{"type":"string","enum":["accesskey","awsIam"],"default":"accesskey","description":"Authentication method for the S3 bucket. Defaults to `accesskey` when omitted. Use `awsIam`\nto delegate authentication to an iClient that holds an AWS IAM role instead of embedding a\nstatic key pair."},"accessKeyId":{"type":"string","description":"AWS access key ID for IAM authentication. From an IAM user or role with S3 permissions\n(s3:GetObject, s3:PutObject, s3:ListBucket, etc.). Used when authType is `accesskey`."},"secretAccessKey":{"type":"string","writeOnly":true,"description":"AWS secret access key, paired with accessKeyId. Used when authType is `accesskey`. Encrypted at rest; returned masked as `\"******\"`."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to an iClient that holds AWS IAM role credentials. Required when authType is\n`awsIam`; ignored otherwise. The iClient must carry `awsIam.roleArn`, and that role's name\nmust start with `celigo-file-adaptor-` — the S3 service assumes only roles in that family,\nso a role created for an HTTP or Redshift connection cannot be reused here."},"pingBucket":{"type":"string","description":"S3 bucket name used for connection health checks (ping). The system performs a HEAD request\non this bucket to verify credentials. Must be a bucket the credentials have access to."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent S3 operations. Applies when `autoRecoverRateLimitErrors` is\nfalse; when auto-recover is on (the default) concurrency auto-scales up to\n`targetConcurrencyLevel` and a `concurrencyLevel` sent on its own is reconciled back. Send no\nmore than the account's licensed maximum.","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaled concurrency when `autoRecoverRateLimitErrors` is true (the\ndefault). The system raises and lowers concurrency between 1 and this value based on\nrate-limit feedback from S3.","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"authType":{"const":"awsIam"}},"required":["authType"]},"then":{"required":["_iClientId"]},"else":{"required":["accessKeyId","secretAccessKey"]}},"HTTP":{"type":"object","description":"Configuration for HTTP/REST API connections. Used when the connection type is \"http\".\nThis is the most versatile connection type in Celigo, supporting any REST, SOAP, or generic HTTP API.\nThe auth.type field selects the authentication strategy; each type requires specific sub-fields.","required":["baseURI","mediaType"],"properties":{"mediaType":{"type":"string","enum":["xml","json","urlencoded","form-data","plaintext"],"description":"Default content type for outbound HTTP request bodies.\nControls the Content-Type header and how request bodies are serialized."},"successMediaType":{"type":"string","enum":["xml","csv","json","plaintext"],"description":"Expected content type of successful API responses. Controls how response bodies are parsed.\nIf omitted, the system infers the format from the response Content-Type header."},"errorMediaType":{"type":"string","enum":["xml","json","plaintext"],"description":"Expected content type of error responses from the API. Controls how error response bodies are parsed for extracting error messages.\n\nIf omitted, defaults to the same format as successMediaType.\n"},"baseURI":{"type":"string","description":"Base URL for all API requests made through this connection. Required.\n\nAll relative URIs in exports and imports are appended to this base URL.\nMust be an absolute URL (e.g., \"https://api.example.com/v2\").\nHandlebars expressions are supported for dynamic URLs — e.g.\n\"https://{{{connection.settings.subdomain}}}.example.com\".\n\nDo NOT include trailing slashes — relative URIs in exports/imports should start with \"/\".\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"disableStrictSSL":{"type":"boolean","description":"When true, disables strict SSL/TLS certificate validation for API requests.\n\nOnly set to true for development/testing with self-signed certificates.\nNEVER disable in production — it removes protection against man-in-the-middle attacks.\n","default":false},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent HTTP requests this connection can make simultaneously.\n\nHigher values increase throughput but may trigger API rate limits.\nSet this based on the target API's rate limit documentation.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\nA decimal is rejected with 422 `invalid_field_value` on every write (the same rule applies to every\nadaptor's `concurrencyLevel` and `targetConcurrencyLevel`, and to `ftp.multiThreadCount`).\nPlatform-managed while `autoRecoverRateLimitErrors` is true — a create or PUT ignores the value (a create without `targetConcurrencyLevel` stores 25 where the license's `concurrency` is at least 25) and the recovery machinery moves it toward the target; set `targetConcurrencyLevel` instead.\nAt level 1 an import's pages run one at a time, so a record's existence lookup and write finish before the next record's start (measured on a single import); the import's `idLockTemplate` serializes only same-key records and leaves the rest parallel.\n","minimum":1,"maximum":50,"default":25},"targetConcurrencyLevel":{"type":"integer","description":"Ceiling the platform climbs back to after rate-limit recovery, in steps of 25% of this value.\nWriting it also sets `concurrencyLevel` to the same value and stops any recovery in progress.\n\nHonored only while `autoRecoverRateLimitErrors` is true; ignored, and unset, when it is false.\n","minimum":1,"maximum":50},"retryHeader":{"type":"string","description":"HTTP response header name that contains the retry delay (in seconds) when rate-limited.\n\nDefaults to \"Retry-After\" which is the HTTP standard. Only change this if the API\nuses a non-standard header name for retry-after values.\n","default":"Retry-After"},"formType":{"type":"string","enum":["assistant","rest","http","graph_ql","assistant_graphql"],"description":"Controls the UI form layout for configuring this connection. Determines which\nfields are shown and how they are organized in the Celigo UI.\nFor programmatic creation, http is the most common choice."},"type":{"type":"string","enum":["Amazon-SP-API","Amazon-Hybrid","vendor_central"],"description":"Selects which Amazon selling program and API family a prebuilt Amazon connection talks to.\nSet by the Amazon Seller Central and Amazon Vendor Central connection forms; a custom\nSelling Partner API integration built on the customer's own developer application is a\nplain HTTP connection and does not carry this field."},"clientCertificates":{"type":"object","description":"Client certificate configuration for mutual TLS (mTLS) authentication.\n\nUse when the API server requires a client certificate to establish the TLS connection.\nYou can provide either a PEM cert/key pair OR a PFX bundle, but not both.\n","properties":{"cert":{"type":"string","description":"Client certificate in PEM format. Must be paired with the key field.\nCannot be used together with pfx.\n"},"key":{"type":"string","description":"Private key for the client certificate in PEM format (encrypted at rest).","writeOnly":true},"ca":{"type":"string","description":"Certificate Authority (CA) certificate in PEM format.\nUse when the server's certificate is signed by a private CA not in the default trust store.\n"},"passphrase":{"type":"string","description":"Passphrase to decrypt an encrypted private key or PFX bundle (encrypted at rest).","writeOnly":true},"pfx":{"type":"string","description":"PKCS#12 (.pfx/.p12) bundle containing both the certificate and private key (encrypted at rest).\nCannot be used together with cert/key.\n","writeOnly":true}}},"ping":{"type":"object","description":"Connection health check (ping) configuration. Defines how Celigo tests\nwhether this connection is alive and authenticated.\n\nWhen configured, Celigo sends an HTTP request to the specified endpoint and\nevaluates the response to determine connection health. The ping runs when\ntesting the connection in the UI and periodically during flow execution.\n","properties":{"relativeURI":{"type":["string","null"],"description":"Relative URI appended to baseURI for the ping request.\nShould be a lightweight, fast endpoint (e.g., \"/me\", \"/health\", \"/api/v1/status\").\nMay be null when no ping endpoint is configured.\n"},"method":{"type":"string","enum":["GET","POST","PUT","HEAD"],"description":"HTTP method for the ping request. Defaults to GET.\nUse POST only if the health endpoint requires it.\n","default":"GET"},"body":{"type":"string","description":"Request body for the ping request. Only used when method is POST or PUT.\nFor form-data mediaType, must be valid multipart form data.\n"},"successPath":{"type":"string","description":"JSON path or XPath expression to extract a success indicator from the ping response.\nIf the value at this path matches one of the successValues, the ping succeeds.\nIf omitted, any 2xx response is considered successful.\n"},"successValues":{"type":"array","items":{"type":"string"},"description":"Values that indicate a successful ping when found at successPath.\nRequires successPath to be set.\n"},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, the value at successPath can be an array and any matching element counts as success."},"failPath":{"type":"string","description":"JSON path or XPath expression to extract a failure indicator from the ping response.\nIf the value at this path matches one of the failValues, the ping fails even if the HTTP status is 2xx.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values that indicate a failed ping when found at failPath.\nRequires failPath to be set.\n"},"errorPath":{"type":"string","description":"JSON path or XPath expression to extract a human-readable error message from\na failed ping response. The extracted message is shown to the user in the UI.\n"}}},"auth":{"type":"object","description":"Authentication configuration for the API connection.\n\nThe auth.type field selects the authentication strategy. Each type requires\nspecific sub-fields — see the type field description for details.\n","properties":{"type":{"type":"string","enum":["custom","basic","token","oauth","wsse","cookie","digest","oauth1","jwtbearer","awsiam"],"description":"Authentication method for this connection. Determines which auth sub-fields are required.\nEach type has its own credential fields; see the x-enumDescriptions for details."},"failStatusCode":{"type":"number","description":"HTTP status code that indicates an authentication failure (e.g., 401, 403).\nWhen this status code is received, the system triggers re-authentication\nbefore retrying the request.\n"},"failPath":{"type":"string","description":"JSON path or XPath expression to check in response bodies for authentication failure indicators.\nUsed when APIs return 200 OK but embed auth errors in the response body.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate an authentication failure.\nRequires failPath to be set.\n"},"failures":{"type":"array","description":"HTTP status codes that indicate an authentication failure and should trigger\nre-authentication. An alternative to failStatusCode that accepts multiple codes.\n","items":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code that signals an authentication failure (e.g., 403)."}}}},"skipFollowAuthorizationHeader":{"type":"boolean","description":"When true, the Authorization header is NOT forwarded on HTTP redirects.\nEnable this for APIs that redirect to a different domain after authentication.\n"},"basic":{"type":"object","description":"Basic authentication credentials. Required when auth.type is \"basic\", \"wsse\", or \"digest\".\n","properties":{"username":{"type":"string","description":"Username for Basic/Digest/WSSE authentication."},"password":{"type":"string","description":"Password for Basic/Digest/WSSE authentication (encrypted at rest). On update, the\nmasked `\"******\"` sent back keeps the stored password; a new value replaces it.","writeOnly":true}}},"token":{"type":"object","description":"Token-based authentication configuration. Required when auth.type is \"token\".\n\nSupports static API keys/bearer tokens and automatic token refresh flows.\nThe token can be sent in a header (Authorization), query parameter, or request body.\n","properties":{"token":{"type":"string","description":"The API key or bearer token value (encrypted at rest); returned masked as `\"******\"`.\nOn update, the mask sent back keeps the stored token; a new value replaces it.\nRequired unless automatic token refresh is configured: a token block without a\ntoken must carry a `refreshMethod`, so a create or update that sends neither fails\nwith 422 `Expected field: refreshMethod to be present.` To create a static-token\nconnection before the real token is available, send a placeholder value and\nreplace it later.\n"},"location":{"type":"string","enum":["url","header","body"],"description":"Where to include the token in outbound requests.\nMost APIs expect header. Use headerName and scheme to control the header format,\nor paramName when sending as a URL query parameter."},"headerName":{"type":"string","description":"HTTP header name for the token when location is \"header\".\nDefaults to \"Authorization\" if omitted.\n"},"scheme":{"type":"string","description":"Token scheme/prefix when sent in a header. Prepended before the token value.\nCommon values: \"Bearer\", \"Token\", \"Basic\".\nExample: scheme \"Bearer\" produces header \"Authorization: Bearer <token>\".\n"},"paramName":{"type":"string","description":"Query parameter name for the token when location is \"url\".\nExample: paramName \"api_key\" produces URL \"?api_key=<token>\".\n"},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for automatic token refresh requests.\nRequired when no static token is provided (refresh-based auth flow).\n","default":"POST"},"refreshRelativeURI":{"type":"string","description":"Relative URI (appended to baseURI) for the token refresh endpoint.\nThe system calls this endpoint to obtain a new token when the current one expires.\n"},"refreshBody":{"type":"string","description":"Request body to send with the token refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml","plaintext"],"description":"Content type for the token refresh request body.\n","default":"urlencoded"},"refreshResponseMediaType":{"type":"string","enum":["json","xml"],"description":"Expected content type of the token refresh response."},"refreshTokenPath":{"type":"string","description":"JSON path to extract the new token from the refresh response.\nExample: \"access_token\" or \"data.token\".\n"},"refreshToken":{"type":"string","description":"Refresh token used to obtain a new access token (encrypted at rest).","writeOnly":true},"refreshTokenLocation":{"type":"string","enum":["header","body"],"description":"Where to include the refresh token in refresh requests."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Additional headers to include in token refresh requests."},"tokenPaths":{"type":"array","items":{"type":"string"},"description":"JSON paths to extract multiple token values from the refresh response.\nUse when the refresh response contains tokens at different paths that need\nto be stored for subsequent requests.\n"},"revoke":{"type":"object","description":"Token-revocation request configuration. When set, the system calls this\nendpoint to revoke the current token (e.g. when the connection is deleted or\nre-authenticated). Used mainly by pre-built HTTP Connector templates.\n","properties":{"uri":{"type":"string","description":"Absolute URL of the token-revocation endpoint."},"body":{"type":"string","description":"Request body to send with the token-revocation request."},"headers":{"type":"array","description":"Additional headers to include in the token-revocation request.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the revocation request."},"value":{"type":"string","description":"Header value to send with the revocation request."}}}}}}}},"oauth":{"$ref":"#/components/schemas/OAuth"},"cookie":{"type":"object","description":"Cookie-based session authentication. Required when auth.type is \"cookie\".\n\nThe system authenticates by sending a request to the login URI, captures the\nsession cookies from the response, and includes them in all subsequent API requests.\n","properties":{"uri":{"type":"string","description":"Login endpoint URI for cookie authentication. Required.\nThe system sends a request to this URI to obtain session cookies.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit.\n"},"body":{"type":"string","description":"Request body for the login request (e.g., JSON with username/password)."},"method":{"type":"string","description":"HTTP method for the login request (typically POST)."},"successStatusCode":{"type":"number","description":"HTTP status code that confirms successful authentication.\nIf the login response returns this status code, the session cookies are captured.\n"}}},"jwt":{"$ref":"#/components/schemas/JWT"}},"if":{"properties":{"type":{"enum":["basic","digest","wsse"]}},"required":["type"]},"then":{"required":["basic"],"properties":{"basic":{"required":["username","password"]}}},"else":{"if":{"properties":{"type":{"const":"token"}},"required":["type"]},"then":{"required":["token"],"properties":{"token":{"required":["token","location"]}}},"else":{"if":{"properties":{"type":{"const":"cookie"}},"required":["type"]},"then":{"required":["cookie"],"properties":{"cookie":{"required":["uri"]}}},"else":{"if":{"properties":{"type":{"const":"jwtbearer"}},"required":["type"]},"then":{"required":["jwt"],"properties":{"jwt":{"required":["signatureMethod","payload"]}},"if":{"properties":{"jwt":{"properties":{"signatureMethod":{"enum":["hmac-sha256","hmac-sha384","hmac-sha512"]}},"required":["signatureMethod"]}},"required":["jwt"]},"then":{"properties":{"jwt":{"required":["signatureMethod","payload","secret"]}}},"else":{"properties":{"jwt":{"required":["signatureMethod","payload","privateKey"]}}}},"else":{"if":{"properties":{"type":{"const":"oauth1"}},"required":["type"]},"then":{"required":["oauth"],"properties":{"oauth":{"required":["oauth1"],"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken"]}}}},"if":{"properties":{"oauth":{"properties":{"oauth1":{"properties":{"signatureMethod":{"enum":["rsa-sha1","rsa-sha256","rsa-sha512"]}},"required":["signatureMethod"]}},"required":["oauth1"]}},"required":["oauth"]},"then":{"properties":{"oauth":{"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken","consumerPrivateKey"]}}}}},"else":{"properties":{"oauth":{"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken","consumerSecret","tokenSecret"]}}}}}}}}}}},"rateLimit":{"type":"object","description":"Rate limiting configuration. Defines how the system detects and handles\nAPI rate limit responses.\n\nWhen rate limiting is detected, the system pauses requests and waits for\nthe retry-after period before resuming. The retryHeader field on the parent\nHTTP object controls which response header contains the wait time.\n","properties":{"failStatusCode":{"type":"number","description":"HTTP status code that indicates the API is rate-limiting requests.\nDefaults to 429 (Too Many Requests) which is the HTTP standard.\nChange only if the API uses a non-standard status code for rate limits.\n","default":429},"failPath":{"type":"string","description":"JSON path or XPath to check in response bodies for rate limit indicators.\nUsed when APIs return 200 OK but embed rate limit errors in the response body.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate rate limiting. Requires failPath to be set.\n"},"limit":{"type":"number","minimum":1,"description":"Maximum number of requests per rate-limit window. When set, the connection's\neffective concurrency level must be 1 to ensure proper rate limit enforcement.\n"}}},"headers":{"type":"array","description":"Default HTTP headers included in every request made through this connection.\nUse for API keys in custom headers, content negotiation, or any headers the API requires on all requests.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name (e.g., \"X-API-Key\", \"Accept\")."},"value":{"type":"string","description":"Header value. Supports handlebars expressions for dynamic values."}},"required":["name","value"]}},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for storing sensitive configuration values (API secrets,\nprivate keys, etc.) that don't fit standard auth fields. Sent as an object of\nfield-name/value pairs; values are encrypted at rest. Returned as the masked\nstring `\"******\"` on responses; on update, that mask sent back keeps the stored values,\nand a new object replaces them. Field definitions are specified in encryptedFields.\n"},"encryptedFields":{"type":"array","description":"Metadata defining the encrypted custom fields available on this connection.\nEach entry describes a field in the encrypted object — its ID, label, and UI position.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the encrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip or help text shown next to the field in the UI."}}}},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive configuration values.\nField definitions are specified in unencryptedFields.","properties":{"marketplaceId":{"type":"string","description":"Amazon marketplace identifier for Amazon connection types."},"sellingRegion":{"type":"string","description":"Amazon selling region for the marketplace."},"googleProjectId":{"type":"string","description":"Google Cloud project id for Google Cloud Storage connections\n(assistant `googlecloudstorage`, or a `baseURI` pointing at\n`storage.googleapis.com`)."}}},"unencryptedFields":{"type":"array","description":"Metadata defining the unencrypted custom fields available on this connection.\nEach entry describes a field in the unencrypted object.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the unencrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip or help text shown next to the field in the UI."},"type":{"type":"string","description":"Field type hint for the UI (e.g., \"text\", \"select\")."}}}},"_iClientId":{"type":"string","format":"objectId","description":"iClient that holds the credentials this connection signs with: the OAuth 2.0 client for\n`auth.type` `oauth` (including the `azureserviceprincipal` service principal an Azure\nData Lake Storage Gen2 connection authenticates with and the `googleserviceaccount` key\na Google Cloud Storage connection uses), or the `awsIam` role for `auth.type` `awsiam`.\nMust belong to the same account as the connection. Omit for every other auth type."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector (pre-built application template) this connection is linked to. Linking\nlets exports and imports on the connection pick endpoints from the connector's catalog and\ndrives the `assistant` form in the UI. The link is resolved server-side on create and on\nany update that changes `assistant` or a connector id, and the result overwrites\n`_httpConnectorId`, `_httpConnectorApiId` and `_httpConnectorVersionId`: an id that does\nnot resolve to an accessible connector is dropped rather than rejected, and when the\ntop-level `assistant` names an application with a legacy adaptor (the connector's\n`legacyId`, e.g. `shopify`) the connector resolved from that slug replaces the id you sent\nand a sent `_httpConnectorVersionId` is dropped. Read the response back to confirm the\nlink took."},"_httpConnectorApiId":{"type":"string","format":"objectId","description":"API within the linked HTTP connector that this connection targets, for connectors that\npublish more than one API. Only meaningful together with `_httpConnectorId`; an id that is\nnot one of that connector's APIs is dropped on save, not rejected."},"_httpConnectorVersionId":{"type":"string","format":"objectId","description":"Version entry of the linked HTTP connector (an item of the connector's `versions` array)\nwhose endpoint definitions this connection uses. Only meaningful together with\n`_httpConnectorId`; an id that is not one of that connector's published versions is\nreplaced by a published version of the connector on create and dropped on update, never\nrejected."},"isRest":{"type":"boolean","description":"When true, this HTTP connection uses REST-style semantics (created from a REST connector template)."},"useNewAuthFailSchema":{"type":"boolean","description":"When true, the connection uses the newer authentication-failure detection schema for refresh/retry handling."}},"if":{"properties":{"type":{"enum":["Amazon-SP-API","Amazon-Hybrid","vendor_central"]}},"required":["type"]},"then":{"required":["unencrypted"],"properties":{"unencrypted":{"required":["marketplaceId","sellingRegion"]}}},"else":{"if":{"properties":{"auth":{"properties":{"type":{"const":"awsiam"}},"required":["type"]}},"required":["auth"]},"then":{"required":["_iClientId"]}}},"OAuth":{"type":"object","description":"OAuth 2.0 and OAuth 1.0a authentication configuration.\nUsed as a sub-object within HTTP and REST connection auth configurations.\nThe grantType field selects the OAuth 2.0 flow; for legacy OAuth 1.0a APIs, use the oauth1 sub-object.","properties":{"type":{"type":"string","enum":["custom","assistant"],"description":"OAuth configuration mode. Controls whether settings are user-configured or\npre-populated by an application assistant connector."},"grantType":{"type":"string","enum":["authorizecode","clientcredentials","password"],"description":"OAuth 2.0 grant type that determines the authentication flow.\nUse authorizecode for user-context integrations, clientcredentials for\nserver-to-server, and password only when the API does not support other flows.","default":"authorizecode"},"authURI":{"type":"string","description":"OAuth 2.0 authorization endpoint URL.\nRequired for \"authorizecode\" grant type. The user is redirected to this URL\nto authorize the application.\nHandlebars expressions are supported for tenant-specific endpoints — e.g.\n\"https://{{{connection.settings.storeName}}}.myshopify.com/admin/oauth/authorize\".\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"tokenURI":{"type":"string","description":"OAuth 2.0 token endpoint URL.\nRequired for \"authorizecode\", \"clientcredentials\", and \"password\" grant types.\nThe system exchanges credentials or authorization codes for access tokens at this URL.\nHandlebars expressions are supported for tenant-specific endpoints.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"skipOauthValidations":{"type":"boolean","description":"When true, skips Celigo's built-in OAuth configuration validation.\nUse when the API has non-standard OAuth requirements that conflict with validation rules.\n","default":false},"scope":{"type":"array","items":{"type":"string"},"description":"OAuth scopes to request during authorization. Controls the level of API access.\nScope values are API-specific (e.g., \"read\", \"write\", \"admin\").\n"},"scopeDelimiter":{"type":"string","description":"Delimiter between multiple scope values. Defaults to a space (\" \") per the\nOAuth 2.0 spec. Some APIs use commas or other delimiters.\n","default":" "},"clientId":{"type":"string","description":"OAuth client ID (application ID) registered with the API provider. An `http`\nconnection takes the app from a `custom_oauth2` iClient referenced by `http._iClientId`\n(an `mcp` connection from `mcp.http._iClientId`) and doesn't store this field: a create\nthat sends `clientId` and `clientSecret` here answers 201 without either (and stores\n`useIClientFields: true` unless `false` is sent).\n"},"clientSecret":{"type":"string","description":"OAuth client secret (encrypted at rest). Not stored on an `http` connection: the secret\nbelongs on the iClient (see `clientId`).\n","writeOnly":true},"username":{"type":"string","description":"Resource owner username. Required when grantType is \"password\".\n"},"password":{"type":"string","description":"Resource owner password (encrypted at rest). Required when grantType is \"password\".\n","writeOnly":true},"clientCredentialsLocation":{"type":"string","enum":["basicauthheader","body"],"description":"Where to send client credentials in token requests. Defaults to basicauthheader\n(HTTP Basic Auth), which is recommended by the OAuth spec. Use body when\nthe API does not support Basic Auth for client credentials.","default":"basicauthheader"},"accessTokenPath":{"type":"string","description":"JSON path to extract the access token from the token endpoint response.\nDefaults to \"access_token\" per the OAuth 2.0 spec.\nChange only if the API returns the token at a non-standard path.\n"},"accessTokenHeaders":{"type":"array","description":"Additional HTTP headers to include in token endpoint requests.\nUse for APIs that require custom headers beyond the standard OAuth parameters.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token request."},"value":{"type":"string","description":"Header value to send with the token request."}}}},"accessTokenBody":{"type":"string","description":"Additional body content to include in token endpoint requests.\nAppended to the standard OAuth parameters.\n"},"oauth2RedirectUrl":{"type":"string","description":"OAuth 2.0 redirect URI (callback URL) registered with the API provider.\nMust exactly match the redirect URI configured in the OAuth application registration.\n"},"useIClientFields":{"type":"boolean","description":"When true, uses iClient-managed OAuth credentials (clientId/clientSecret)\ninstead of the values in this configuration. The iClient is the connection's\n`_iClientId` — on an HTTP connection `http._iClientId`, beside `auth`, not inside it —\nand it also supplies the grant type and the authorization and token endpoints, so a\ncreate needs only `auth.type: \"oauth\"`, `auth.oauth.useIClientFields: true` and the\niClient id. The connection holds no tokens until a person completes the authorization\nin a browser.\n"},"oauth1":{"type":"object","description":"OAuth 1.0a configuration for legacy APIs that use the older OAuth protocol.\nAlways needs consumerKey and accessToken; HMAC signature methods also need\nconsumerSecret and tokenSecret, while RSA methods need consumerPrivateKey.","properties":{"consumerKey":{"type":"string","description":"OAuth 1.0a consumer key (API key).\nIdentifies the application making the request.\n"},"consumerSecret":{"type":"string","description":"OAuth 1.0a consumer secret (encrypted at rest).\nRequired for HMAC and PLAINTEXT signature methods.\n","writeOnly":true},"accessToken":{"type":"string","description":"OAuth 1.0a access token (encrypted at rest).\nRepresents the user's authorization for the application to access their data.\n","writeOnly":true},"tokenSecret":{"type":"string","description":"OAuth 1.0a token secret (encrypted at rest).\nRequired for HMAC and PLAINTEXT signature methods.\n","writeOnly":true},"signatureMethod":{"type":"string","enum":["hmac-sha1","hmac-sha256","hmac-sha512","rsa-sha1","rsa-sha256","rsa-sha512","plaintext"],"description":"OAuth 1.0a request signing method. HMAC methods require consumerSecret and\ntokenSecret; RSA methods require consumerPrivateKey. PLAINTEXT offers no\ncryptographic signing and should only be used for testing over HTTPS."},"consumerPrivateKey":{"type":"string","description":"RSA private key for OAuth 1.0a RSA signature methods (encrypted at rest).\nRequired when signatureMethod is RSA-SHA1, RSA-SHA256, or RSA-SHA512.\n","writeOnly":true},"realm":{"type":"string","description":"OAuth realm value included in the Authorization header.\nSome APIs require this to identify the authentication domain.\n"}}},"pkceCodeVerifier":{"type":"string","description":"PKCE (Proof Key for Code Exchange) code verifier for enhanced OAuth 2.0 security.\nManaged internally by the system during authorization code flows.\n","writeOnly":true}},"if":{"properties":{"grantType":{"const":"authorizecode"}},"required":["grantType"]},"then":{"required":["authURI","tokenURI"]},"else":{"if":{"properties":{"grantType":{"const":"clientcredentials"}},"required":["grantType"]},"then":{"required":["tokenURI"]},"else":{"if":{"properties":{"grantType":{"const":"password"}},"required":["grantType"]},"then":{"required":["tokenURI","username","password"]}}}},"JWT":{"type":"object","description":"JWT Bearer authentication configuration. Used when auth.type is \"jwtbearer\" on HTTP\nconnections. The connection builds a JWT from payload and headers, signs it using\nsignatureMethod, and sends it as the bearer token. HMAC methods sign with secret;\nRSA/ECDSA/PSS methods sign with privateKey.","properties":{"signatureMethod":{"type":"string","enum":["hmac-sha256","hmac-sha384","hmac-sha512","rsa-sha256","rsa-sha384","rsa-sha512","es256","es384","es512","ps256","ps384","ps512"],"description":"JWT signing method. Required when auth.type is \"jwtbearer\". HMAC methods require\nthe secret field; RSA/ECDSA/PSS methods require the privateKey field."},"payload":{"type":"object","additionalProperties":true,"description":"JWT claims payload (the token body). Required and must be non-empty when auth.type\nis \"jwtbearer\". Keys are JWT claim names (e.g. iss, sub, aud, exp)."},"headers":{"type":"object","additionalProperties":true,"description":"JWT header parameters merged into the generated token header (e.g. kid)."},"secret":{"type":"string","writeOnly":true,"description":"Shared secret for HMAC signature methods (hmac-sha256/hmac-sha512), encrypted at rest.\nRequired when signatureMethod is an HMAC method."},"isSecretBase64Encoded":{"type":"boolean","description":"When true, the secret is base64-decoded before being used to sign."},"privateKey":{"type":"string","writeOnly":true,"description":"PEM-encoded private key for RSA/ECDSA/PSS signature methods, encrypted at rest.\nRequired for any rsa-*, es*, or ps* signature method."},"token":{"type":"string","writeOnly":true,"description":"Pre-generated static JWT to use instead of building one from payload (encrypted at rest).\nUse only when the API issues a long-lived JWT that does not need regeneration."}},"if":{"properties":{"signatureMethod":{"enum":["hmac-sha256","hmac-sha384","hmac-sha512"]}},"required":["signatureMethod"]},"then":{"required":["secret"]},"else":{"if":{"properties":{"signatureMethod":{"enum":["rsa-sha256","rsa-sha384","rsa-sha512","es256","es384","es512","ps256","ps384","ps512"]}},"required":["signatureMethod"]},"then":{"required":["privateKey"]}}},"RDBMS":{"type":"object","description":"Configuration for relational database connections. Used when the connection type is \"rdbms\".\nThe type field selects the database system, which determines the SQL dialect, connection driver,\ndefault port, and which additional sub-fields are required.","required":["type"],"properties":{"type":{"type":"string","enum":["mysql","postgresql","mssql","snowflake","oracle","bigquery","redshift","mariadb","azuresynapse"],"description":"The specific relational database system to connect to. Determines the SQL dialect,\nconnection driver, default port, and which additional sub-fields are required."},"host":{"type":"string","description":"Database server hostname or IP address.\nRequired for all types except BigQuery (which uses Google's API endpoints) and Redshift\n(which is reached through its cluster identifier and region instead of a host).\n\nFor Snowflake, use the account URL format: \"account_identifier.snowflakecomputing.com\".\n"},"port":{"type":"number","description":"Database server port number. If omitted, uses the default port for the database type:\n- MySQL/MariaDB: 3306\n- PostgreSQL: 5432\n- MS SQL/Azure Synapse: 1433\n- Oracle: 1521\n- Snowflake: 443\n- Redshift: 5439\n","minimum":1,"maximum":65535},"database":{"type":"string","description":"Database name to connect to. Required for most types.\n\nFor Oracle, use the serviceName field instead of database.\nFor BigQuery, use bigquery.dataset to specify the target dataset.\n"},"instanceName":{"type":"string","description":"Named instance identifier, used when the server hosts multiple named database instances\n(primarily MS SQL Server). Leave empty for a default instance.\n"},"user":{"type":"string","description":"Database username for authentication. Required for all types except\nBigQuery (service account auth), Redshift, and `mssql` / `azuresynapse`\nwith `mssql.authType=azure-service-principal`, where the Entra principal\nin the iClient signs in and a `user` sent anyway is stored unused.\n"},"password":{"type":"string","description":"Database password (encrypted at rest). Required alongside user for password-based auth.","writeOnly":true},"version":{"type":"string","enum":["SQL Server 2008 R2","SQL Server 2012","SQL Server 2014","SQL Server 2016","SQL Server 2017","Azure"],"description":"SQL Server engine version, which selects driver compatibility behavior. Applies to mssql\nand azuresynapse connections only (azuresynapse is always \"Azure\")."},"serviceName":{"type":"string","description":"Oracle service name, supplied instead of the database field for Oracle connections.\nThis is the TNS service name or pluggable database (PDB) service name.\n"},"serverType":{"type":"string","enum":["dedicated","shared","pooled"],"description":"Oracle server connection type. Controls the server process model used for connections."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent database connections.\nSet based on the database server's connection limit and available resources.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts the number of\nconcurrent connections between 1 and this value based on performance feedback.\n","minimum":1,"maximum":50},"disableStrictSSL":{"type":"boolean","description":"When true, disables strict SSL/TLS certificate validation for the database connection.\nOnly use for development/testing with self-signed certificates.\n","default":false},"snowflake":{"type":"object","description":"Snowflake-specific configuration. Required when type is \"snowflake\".\n","required":["authType"],"properties":{"warehouse":{"type":"string","description":"Snowflake virtual warehouse that provides compute resources for queries.\nMust be a warehouse the user's role can access."},"schema":{"type":"string","description":"Default Snowflake schema. If omitted, queries must fully-qualify table names\n(e.g., DATABASE.SCHEMA.TABLE).\n"},"role":{"type":"string","description":"Snowflake security role to use for the session. Determines which databases,\nschemas, and warehouses are accessible. Defaults to the user's default role.\n"},"authType":{"type":"string","enum":["keyPair"],"description":"Authentication type for Snowflake. keyPair uses RSA key-pair authentication and requires\nthe connection's key field. It is the only type the connection form offers for new\nconnections (password-based auth is no longer available)."}}},"mssql":{"type":"object","description":"Microsoft SQL Server / Azure Synapse-specific configuration. Read for\nboth the `mssql` and the `azuresynapse` types — Azure Synapse\nAnalytics shares SQL Server's authentication model and this\nsub-object.","properties":{"authType":{"type":"string","enum":["basic","azure-service-principal"],"description":"How a Microsoft SQL Server or Azure Synapse connection\nauthenticates. Defaults to `basic` when omitted (the connection\nform's \"Database user\"). With `azure-service-principal` the\nconnection signs in as the Entra application registered in the\niClient — a client secret, or on SQL Server a certificate — and\n`_iClientId` must reference it. The SQL Server connection form\noffers `azure-service-principal` in Cloud mode only and saves\n`basic` for an on-premise connection (`_agentId` set).","default":"basic"}}},"bigquery":{"type":"object","description":"Google BigQuery-specific configuration. Required when type is \"bigquery\".\nUses Google Cloud service account credentials for authentication.\n","properties":{"projectId":{"type":"string","description":"Google Cloud project ID that contains the BigQuery datasets.\nFound in the Google Cloud Console project settings.\n"},"dataset":{"type":"string","description":"Default BigQuery dataset name.\nQueries will target tables within this dataset unless fully-qualified names are used.\n"},"clientEmail":{"type":"string","format":"email","description":"Google Cloud service account email address.\nThe service account must have BigQuery Data Editor and BigQuery Job User roles.\n"},"privateKey":{"type":"string","description":"Google Cloud service account private key in PEM format (encrypted at rest).\nDownloaded as part of the service account JSON key file.\n","writeOnly":true}}},"redshift":{"type":"object","description":"Amazon Redshift-specific configuration. `region` is always required.\nCredentials depend on `authType`: static access keys in `aws` for\n`accesskey` (the default), or an `awsIam` iClient referenced by\n`rdbms._iClientId` for `awsIam`. The top-level user and password are optional.\n","properties":{"authType":{"type":"string","enum":["accesskey","awsIam"],"default":"accesskey","description":"Selects the Redshift authentication mode; omitting it behaves as\n`accesskey`. With `awsIam`, the platform assumes the iClient's\nrole and requires exactly one of `clusterIdentifier` (provisioned\ncluster) or `workgroupName` (Redshift Serverless) — supplying\nboth or neither fails with 422. A bulk-load import saves against\neither mode, cluster or Serverless workgroup alike."},"aws":{"type":"object","description":"Static AWS access keys, used when `authType` is `accesskey` (or\nomitted). Not used with `awsIam` — credentials then come from the\niClient.","properties":{"accessKeyId":{"type":"string","description":"AWS access key ID for IAM authentication."},"secretAccessKey":{"type":"string","description":"AWS secret access key (encrypted at rest).","writeOnly":true}}},"clusterIdentifier":{"type":"string","description":"Redshift cluster identifier, used with the region to reach a\nprovisioned cluster. With `awsIam` auth, exactly one of\n`clusterIdentifier` or `workgroupName` must be set."},"workgroupName":{"type":"string","description":"Redshift Serverless workgroup to connect to instead of a\nprovisioned cluster. Only valid when `authType` is `awsIam` —\nthe API rejects it with `accesskey` auth (422 \"Redshift\nServerless (workgroupName) requires authType=awsIam\") — and is\nmutually exclusive with `clusterIdentifier`."},"region":{"type":"string","description":"AWS region where the Redshift cluster is deployed.\n","enum":["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-north-1","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","ap-south-1","sa-east-1","ca-central-1"]}}},"ssl":{"$ref":"#/components/schemas/SSL"},"options":{"type":"array","description":"Additional database driver connection options as name/value pairs.\nUse for driver-specific settings not covered by the standard fields\n(e.g., connection timeout, charset, application name).\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Option name (driver-specific)."},"value":{"type":"string","description":"Option value."}},"required":["name","value"]}},"key":{"type":"string","writeOnly":true,"description":"RSA private key (PEM-encoded, encrypted at rest). Required when type is `snowflake`\nand `snowflake.authType` is `keyPair`. Not used by any other database type."},"passphrase":{"type":"string","writeOnly":true,"description":"Passphrase that decrypts the RSA private key in the key field, when that key is\nencrypted (encrypted at rest). Used only for `snowflake` with `snowflake.authType`\n`keyPair`; omit when the private key is unencrypted."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to an iClient holding auth credentials, stored inside the\nrdbms object. Required when type is `mssql` or `azuresynapse` and\n`mssql.authType` is `azure-service-principal` (an\n`azureserviceprincipal` iClient — the Microsoft Entra tenant id,\nclient id and client secret or certificate), and when type is\n`redshift` and `redshift.authType` is `awsIam` (an `awsIam`-provider\niClient holding the role ARN to assume). On `mssql` / `azuresynapse`\nit is rejected when `mssql.authType` is `basic` or omitted. For\nRedshift the iClient must carry `awsIam.roleArn`, and that role's name\nmust start with `celigo-data-warehouse-adaptor-` — the data-warehouse\nservice assumes only roles in that family, so a role created for an S3\nor HTTP connection cannot be reused here."}},"if":{"properties":{"type":{"enum":["mysql","postgresql","mariadb"]}},"required":["type"]},"then":{"required":["host","database","user","password"]},"else":{"if":{"properties":{"type":{"const":"mssql"}},"required":["type"]},"then":{"if":{"properties":{"mssql":{"properties":{"authType":{"const":"azure-service-principal"}},"required":["authType"]}},"required":["mssql"]},"then":{"required":["host","database","version","_iClientId"]},"else":{"required":["host","database","version","user","password"]}},"else":{"if":{"properties":{"type":{"const":"azuresynapse"}},"required":["type"]},"then":{"if":{"properties":{"mssql":{"properties":{"authType":{"const":"azure-service-principal"}},"required":["authType"]}},"required":["mssql"]},"then":{"required":["host","database","_iClientId"]},"else":{"required":["host","database","user","password"]}},"else":{"if":{"properties":{"type":{"const":"snowflake"}},"required":["type"]},"then":{"required":["host","database","user"],"properties":{"snowflake":{"required":["authType","warehouse"]}},"if":{"properties":{"snowflake":{"properties":{"authType":{"const":"keyPair"}},"required":["authType"]}},"required":["snowflake"]},"then":{"required":["key"]},"else":{"required":["password"]}},"else":{"if":{"properties":{"type":{"const":"oracle"}},"required":["type"]},"then":{"required":["host","user","password"]},"else":{"if":{"properties":{"type":{"const":"bigquery"}},"required":["type"]},"then":{"required":["bigquery"],"properties":{"bigquery":{"required":["projectId","dataset","clientEmail","privateKey"]}}},"else":{"if":{"properties":{"type":{"const":"redshift"}},"required":["type"]},"then":{"required":["database","user","redshift"],"properties":{"redshift":{"required":["region"]}},"if":{"required":["redshift"],"properties":{"redshift":{"required":["authType"],"properties":{"authType":{"const":"awsIam"}}}}},"then":{"required":["_iClientId"],"properties":{"redshift":{"oneOf":[{"required":["clusterIdentifier"],"not":{"required":["workgroupName"]}},{"required":["workgroupName"],"not":{"required":["clusterIdentifier"]}}]}}},"else":{"properties":{"redshift":{"required":["aws","clusterIdentifier"],"not":{"required":["workgroupName"]},"properties":{"aws":{"required":["accessKeyId","secretAccessKey"]}}}}}}}}}}}}},"MongoDB":{"type":"object","description":"Configuration for MongoDB connections. Used when the connection type is \"mongodb\". Supports\nstandalone instances, replica sets, and MongoDB Atlas clusters. For a replica set, list all\nmember addresses in host and set replicaSet to the set name; authSource selects the\nauthentication database when it differs from the target database.","required":["host","username","password"],"properties":{"host":{"type":"array","minItems":1,"items":{"type":"string"},"description":"MongoDB server addresses. An array of one or more host:port strings.\n\n- Standalone: [\"mongodb.example.com:27017\"]\n- Replica set: [\"rs1.example.com:27017\", \"rs2.example.com:27017\", \"rs3.example.com:27017\"]\n- MongoDB Atlas: [\"cluster0-shard-00-00.abc.mongodb.net:27017\", ...]\n\nInclude the port number with each host. Default MongoDB port is 27017.\n"},"database":{"type":"string","description":"Target MongoDB database name.\nAll operations (reads/writes) target collections within this database.\nOptional on the connection — when omitted, set the database per operation instead.\n"},"username":{"type":"string","description":"MongoDB username for authentication."},"password":{"type":"string","writeOnly":true,"description":"MongoDB password. Write-only — accepted on create/update and returned masked as `\"******\"`."},"replicaSet":{"type":"string","description":"MongoDB replica set name. Set this when connecting to a replica set so the driver can\ndiscover all members and handle failover. For MongoDB Atlas, this is typically\n\"atlas-xxxxxx-shard-0\".\n"},"ssl":{"type":"boolean","description":"When true, connects to MongoDB over TLS/SSL.\nRequired for MongoDB Atlas and recommended for all production deployments.\n","default":false},"authSource":{"type":"string","description":"MongoDB authentication database — the database where the user credentials are stored.\nDefaults to the value of the database field. Set to \"admin\" if the user was created\nin the admin database (common for shared MongoDB deployments and Atlas).\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent MongoDB operations.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on rate limit feedback.\n\nOnly relevant when autoRecoverRateLimitErrors is enabled on the connection.\n","minimum":1,"maximum":50,"default":5}}},"AS2":{"type":"object","description":"AS2 (Applicability Statement 2) connection configuration for EDI","required":["as2Id","partnerId","partnerStationInfo","userStationInfo"],"properties":{"as2Id":{"type":"string","description":"AS2 identifier for this station. Trading partners use this as the \"To\"\nidentifier when sending documents, and integrator.io uses it as the \"From\"\nidentifier when sending documents to partners.\n\nMust be unique across ALL integrator.io users so inbound documents route\ncorrectly. Set on creation and cannot be changed afterward — a PUT with a\ndifferent value is ignored. Use a distinct identifier per environment\n(e.g. production vs. non-production). If omitted, a unique value is auto-generated.\n"},"partnerId":{"type":"string","description":"Trading partner's AS2 identifier — the partner's \"From\" identifier on documents they\nsend and the \"To\" identifier integrator.io uses when sending to them. Set on creation\nand cannot be changed afterward; a PUT with a different value is ignored."},"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading partner connector this AS2 connection was provisioned from during partner onboarding. Omit for a standalone AS2 connection."},"contentBasedFlowRouter":{"type":"object","description":"Routes inbound documents to different flows based on message content, for connections\nshared across multiple flows. Omit unless a routing script is required.","properties":{"function":{"type":"string","description":"Function in the routing script that returns the target flow."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."}}},"partnerStationInfo":{"type":"object","description":"Partner (remote) station configuration, used on the IMPORT side — controls how messages\nare sent TO the trading partner.","required":["as2URI","signing","encryptionType"],"properties":{"as2URI":{"type":"string","format":"uri","description":"Partner's AS2 endpoint that integrator.io posts outbound messages to.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data\nsent to an HTTP endpoint is not encrypted and may be intercepted or modified in transit."},"mdn":{"type":"object","description":"Settings for the MDN (Message Disposition Notification) receipt the partner returns for outbound messages.","required":["mdnSigning"],"properties":{"mdnURL":{"type":"string","format":"uri","description":"Endpoint the partner posts asynchronous MDNs to. Set only when the partner\nreturns MDNs asynchronously rather than on the same connection.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit."},"signatureProtocol":{"type":"string","enum":["pkcs7-signature"],"description":"Signature protocol the partner uses on returned MDNs."},"mdnSigning":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm used to verify the signature on MDNs the partner returns. Defaults to NONE when the partner does not sign MDNs."},"verifyMDNSignature":{"type":"boolean","description":"When true, verifies the signature on MDNs returned by the partner. Requires unencrypted.partnerCertificate."}}},"auth":{"type":"object","description":"Authentication for posting messages to the partner's AS2 endpoint. Omit (or set\ntype to none) when the endpoint is unauthenticated.","properties":{"type":{"type":"string","enum":["basic","token","none"],"description":"Authentication scheme for the partner endpoint. Set the matching basic or token sub-object for basic or token."},"failStatusCode":{"type":"number","description":"HTTP status code in the partner's response that signals an authentication failure, triggering a token refresh or error."},"failPath":{"type":"string","description":"Path in the partner's JSON response body checked against failValues to detect an authentication failure."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate an authentication failure. Requires failPath."},"basic":{"type":"object","description":"Credentials for basic authentication. Present when type is basic.","properties":{"username":{"type":"string","description":"Username for basic authentication."},"password":{"type":"string","writeOnly":true,"description":"Password for basic authentication. Masked as \"******\" in GET responses."}}},"token":{"type":"object","description":"Token configuration. Present when type is token.","properties":{"token":{"type":"string","writeOnly":true,"description":"Bearer/access token sent with each request to the partner. Masked as \"******\" in GET responses."},"location":{"type":"string","enum":["header","url","body"],"description":"Where to place the token in the outbound request."},"headerName":{"type":"string","description":"Header name carrying the token when location is header. Defaults to Authorization."},"scheme":{"type":"string","enum":["bearer","mac","oauth","none"],"description":"Authorization scheme prepended to the token when location is header."},"paramName":{"type":"string","description":"Query parameter name carrying the token when location is url."},"refreshToken":{"type":"string","writeOnly":true,"description":"Token used to obtain a new access token when the current one expires. Masked as \"******\" in GET responses."},"refreshRelativeURI":{"type":"string","description":"Endpoint, relative to the partner's host, called to refresh the token."},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for the token-refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml"],"description":"Content type of the token-refresh request body."},"refreshBody":{"type":"string","description":"Request body sent with the token-refresh request, used when refreshMethod is POST or PUT."},"refreshTokenPath":{"type":"string","description":"Path in the refresh response body where the new access token is found."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Headers sent with the token-refresh request."}}}}},"rateLimit":{"type":"object","description":"Throttles requests to the partner endpoint when it enforces a non-standard rate limit.","properties":{"failStatusCode":{"type":"number","description":"HTTP status code in the partner's response that indicates rate limiting."},"failPath":{"type":"string","description":"Path in the partner's JSON response body checked against failValues to detect rate limiting."},"failValues":{"type":"array","description":"Values at failPath that indicate rate limiting. Requires failPath.","items":{"type":"string"}},"limit":{"type":"number","minimum":1,"description":"Wait time in milliseconds between requests to the partner endpoint."}}},"SMIMEVersion":{"type":"string","enum":["v2","v3"],"description":"S/MIME version applied to outbound messages. Not exposed in the connection form."},"signing":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm for signing messages sent to the partner. Any value other than NONE requires encrypted.userPrivateKey and unencrypted.userPublicKey."},"encryptionType":{"type":"string","enum":["NONE","DES","RC2","3DES","AES128","AES256"],"description":"Cipher for encrypting messages sent to the partner. Any value other than NONE requires unencrypted.partnerCertificate."},"encoding":{"type":"string","enum":["base64","binary"],"description":"Content transfer encoding for outbound messages. Shown in the form only when encryptionType is not NONE."},"signatureEncoding":{"type":"string","enum":["base64","binary"],"description":"Encoding applied to the digital signature on outbound messages."}}},"userStationInfo":{"type":"object","description":"User (local) station configuration, used on the EXPORT side — controls how inbound\nmessages from the partner are processed.","required":["signing","encryptionType"],"properties":{"mdn":{"type":"object","description":"Settings for the MDN receipt this station returns to the partner for inbound messages.","required":["mdnSigning"],"properties":{"mdnURL":{"type":"string","anyOf":[{"format":"uri"},{"const":""}],"description":"Partner's endpoint this station posts asynchronous MDNs to. Set only when\nthe partner requires asynchronous MDNs; stored as an empty string otherwise.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit."},"signatureProtocol":{"type":"string","enum":["pkcs7-signature"],"description":"Signature protocol applied to MDNs this station returns."},"mdnSigning":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm used to sign MDNs this station returns to the partner. Signs the MDN\nonly — the hash algorithm of its `Received-Content-MIC` follows\nuserStationInfo.signing, not this field."},"mdnEncoding":{"type":"string","enum":["base64","binary"],"description":"Encoding applied to MDNs this station returns."}}},"signing":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm for verifying signatures on inbound messages; the same algorithm is used\nfor the `Received-Content-MIC` in the MDN returned for each message (NONE falls back to\nSHA-1, and the algorithm the partner requests in `Disposition-Notification-Options` is\nnot used). The MIC is computed when a message is received, so a change here applies only\nto messages received afterwards — the partner must resend to get an MDN with the new\nalgorithm. Any value other than NONE requires unencrypted.partnerCertificate."},"encryptionType":{"type":"string","enum":["NONE","DES","RC2","3DES","AES128","AES256"],"description":"Cipher for decrypting inbound messages. Any value other than NONE requires encrypted.userPrivateKey and unencrypted.userPublicKey."},"encoding":{"type":"string","enum":["base64","binary"],"description":"Content transfer encoding expected on inbound messages. Shown in the form only when encryptionType is not NONE."},"compressed":{"type":"boolean","description":"When true, message content is compressed. Not exposed in the connection form.","default":false}}},"encrypted":{"type":"object","description":"Encrypted-at-rest key material for this station's own identity. Supply when this station\nsigns outbound messages or decrypts inbound messages; integrator.io injects an\nauto-generated self-signed key otherwise.","properties":{"userPrivateKey":{"type":"string","writeOnly":true,"description":"PEM-encoded X.509 private key for this station, used to sign outbound messages and\ndecrypt inbound ones. Masked as \"******\" in GET responses. Required when\npartnerStationInfo.signing is not NONE or userStationInfo.encryptionType is not NONE."}}},"unencrypted":{"type":"object","description":"Public certificate material for this station and the partner. integrator.io injects an\nauto-generated self-signed certificate for this station when none is supplied.","properties":{"userPublicKey":{"type":"string","description":"PEM-encoded X.509 public certificate for this station, paired with\nencrypted.userPrivateKey. Required when partnerStationInfo.signing is not NONE or\nuserStationInfo.encryptionType is not NONE."},"partnerCertificate":{"type":"string","description":"PEM-encoded X.509 certificate for the trading partner, used to encrypt outbound\nmessages and verify inbound signatures and MDNs. Required when\npartnerStationInfo.encryptionType is not NONE, userStationInfo.signing is not NONE,\nor partnerStationInfo.mdn.verifyMDNSignature is true."}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of messages processed concurrently for this connection. The default of 5\nis safe for most partners. Send no more than the account's licensed maximum (25 standard,\n50 with an Environments license).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Concurrency ceiling integrator.io scales up to when auto-recovering from rate-limit\nerrors. Only applies when autoRecoverRateLimitErrors is true on the connection.","minimum":1,"maximum":50},"preventCanonicalization":{"type":"boolean","description":"When true, inbound messages are verified — and the `Received-Content-MIC` in the returned\nMDN is computed — over the content exactly as received, without first normalizing line\nendings to CRLF; the partner's MDN signatures are verified the same way. Enable only when a\npartner reports signature-verification failures or MIC mismatches caused by\ncanonicalization.","default":false}}},"Filesystem":{"type":"object","description":"Configuration for filesystem connections. Used when the connection type is \"filesystem\".\nProvides access to directories on a Celigo on-premise Agent's host or mounted network\ndrives, so a connection-level `_agentId` is required — cloud-only deployments cannot use\nthis type. File-based PGP encryption/decryption is configured through the connection-level\n`pgp` object.","properties":{"ping":{"type":"object","description":"Connection health-check configuration. integrator.io reads this directory to verify the agent can reach the filesystem.","properties":{"directoryPath":{"type":"string","description":"Absolute directory path the agent checks to confirm filesystem access. Accepts a POSIX path,\na Windows drive path, or a UNC share. Leave unset to skip the directory check during ping."}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of files processed concurrently. Send no more than `targetConcurrencyLevel` and\nthe account's licensed maximum (25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":1},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaling. The agent scales concurrency between 1 and this value based on\nthroughput, so it also caps `concurrencyLevel`. Send no more than the account's licensed maximum\n(25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":1}}},"MCP":{"type":"object","description":"Configuration for MCP (Model Context Protocol) connections. Used when the connection type\nis \"mcp\". Lets Celigo call tools exposed by an external MCP server over HTTP. Authentication\ngoes through the http sub-object, which reuses the HTTP auth config but accepts only the\ntoken, oauth, and custom auth types.","required":["serverURL","http"],"properties":{"protocol":{"type":"string","enum":["http"],"default":"http","readOnly":true,"description":"Transport protocol for communicating with the MCP server.\nCurrently only \"http\" is supported; the server sets this automatically and ignores other values.\n"},"serverURL":{"type":"string","format":"uri","description":"MCP server endpoint URL. Must be a valid absolute URL\n(e.g. \"https://mcp-server.example.com/mcp\").\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit."},"timeout":{"type":"number","default":600000,"description":"Request timeout in milliseconds for MCP tool invocations.\nIf the MCP server does not respond within this time, the request fails.\nDefaults to 600000 (10 minutes) when omitted.\n"},"allowedTools":{"type":"array","description":"Optional allowlist of MCP tool names that this connection may invoke.\nWhen set, only tools in this list can be called. When omitted or empty,\nall tools exposed by the MCP server are available.\n","items":{"type":"string"}},"http":{"type":"object","required":["auth"],"description":"HTTP transport configuration for the MCP connection, including authentication and headers.\n","properties":{"_iClientId":{"type":"string","format":"objectId","description":"Reference to an OAuth iClient for OAuth-based MCP authentication.\nRequired when http.auth.type is \"oauth\".\n"},"auth":{"type":"object","required":["type"],"description":"Authentication configuration for the MCP connection. The auth.type field selects the\nstrategy. MCP supports only token, oauth, and custom — other HTTP auth types\n(basic, wsse, cookie, jwt, etc.) are rejected with a 422.\n","properties":{"type":{"type":"string","enum":["token","oauth","custom"],"description":"Authentication method for the MCP server. Determines which auth sub-fields apply."},"token":{"$ref":"#/components/schemas/token"},"oauth":{"$ref":"#/components/schemas/OAuth"}}},"headers":{"type":"array","description":"Default HTTP headers included in every request to the MCP server.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value. Supports handlebars expressions for dynamic values."}},"required":["name","value"]}},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive MCP configuration."},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for sensitive MCP configuration. Sent as an object;\nreturned as the masked string `\"******\"` on responses."}},"if":{"properties":{"auth":{"properties":{"type":{"const":"token"}},"required":["type"]}},"required":["auth"]},"then":{"properties":{"auth":{"required":["token"],"properties":{"token":{"required":["token"]}}}}},"else":{"if":{"properties":{"auth":{"properties":{"type":{"const":"oauth"}},"required":["type"]}},"required":["auth"]},"then":{"required":["_iClientId"]}}}}},"token":{"type":"object","description":"Token-based authentication configuration. Required when auth.type is \"token\".\n\nSupports static API keys/bearer tokens and automatic token refresh flows.\nThe token can be sent in a header (Authorization), query parameter, or request body.\n","properties":{"token":{"type":"string","description":"The API key or bearer token value (encrypted at rest); returned masked as `\"******\"`.\nOn update, the mask sent back keeps the stored token; a new value replaces it.\nRequired unless automatic token refresh is configured: a token block without a\ntoken must carry a `refreshMethod`, so a create or update that sends neither fails\nwith 422 `Expected field: refreshMethod to be present.` To create a static-token\nconnection before the real token is available, send a placeholder value and\nreplace it later.\n"},"location":{"type":"string","enum":["url","header","body"],"description":"Where to include the token in outbound requests.\nMost APIs expect header. Use headerName and scheme to control the header format,\nor paramName when sending as a URL query parameter."},"headerName":{"type":"string","description":"HTTP header name for the token when location is \"header\".\nDefaults to \"Authorization\" if omitted.\n"},"scheme":{"type":"string","description":"Token scheme/prefix when sent in a header. Prepended before the token value.\nCommon values: \"Bearer\", \"Token\", \"Basic\".\nExample: scheme \"Bearer\" produces header \"Authorization: Bearer <token>\".\n"},"paramName":{"type":"string","description":"Query parameter name for the token when location is \"url\".\nExample: paramName \"api_key\" produces URL \"?api_key=<token>\".\n"},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for automatic token refresh requests.\nRequired when no static token is provided (refresh-based auth flow).\n","default":"POST"},"refreshRelativeURI":{"type":"string","description":"Relative URI (appended to baseURI) for the token refresh endpoint.\nThe system calls this endpoint to obtain a new token when the current one expires.\n"},"refreshBody":{"type":"string","description":"Request body to send with the token refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml","plaintext"],"description":"Content type for the token refresh request body.\n","default":"urlencoded"},"refreshResponseMediaType":{"type":"string","enum":["json","xml"],"description":"Expected content type of the token refresh response."},"refreshTokenPath":{"type":"string","description":"JSON path to extract the new token from the refresh response.\nExample: \"access_token\" or \"data.token\".\n"},"refreshToken":{"type":"string","description":"Refresh token used to obtain a new access token (encrypted at rest).","writeOnly":true},"refreshTokenLocation":{"type":"string","enum":["header","body"],"description":"Where to include the refresh token in refresh requests."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Additional headers to include in token refresh requests."},"tokenPaths":{"type":"array","items":{"type":"string"},"description":"JSON paths to extract multiple token values from the refresh response.\nUse when the refresh response contains tokens at different paths that need\nto be stored for subsequent requests.\n"},"revoke":{"type":"object","description":"Token-revocation request configuration. When set, the system calls this\nendpoint to revoke the current token (e.g. when the connection is deleted or\nre-authenticated). Used mainly by pre-built HTTP Connector templates.\n","properties":{"uri":{"type":"string","description":"Absolute URL of the token-revocation endpoint."},"body":{"type":"string","description":"Request body to send with the token-revocation request."},"headers":{"type":"array","description":"Additional headers to include in the token-revocation request.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the revocation request."},"value":{"type":"string","description":"Header value to send with the revocation request."}}}}}}}},"DynamoDB":{"type":"object","description":"Configuration for Amazon DynamoDB connections. Used when the connection type is \"dynamodb\".\nAuthenticates with AWS IAM access keys, which must grant the DynamoDB actions the integration\nuses (GetItem, PutItem, Query, Scan, etc.). The AWS region is resolved per table at request\ntime, so no region is stored on the connection.","required":["aws"],"properties":{"aws":{"type":"object","description":"AWS IAM access-key credentials used to sign DynamoDB requests.","required":["accessKeyId","secretAccessKey"],"properties":{"accessKeyId":{"type":"string","description":"Access key ID of the IAM user or role whose policy grants the required DynamoDB actions."},"secretAccessKey":{"type":"string","description":"Secret access key paired with `accessKeyId`. Encrypted at rest and returned masked as `\"******\"`.","writeOnly":true}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of DynamoDB requests this connection runs at once.\n\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Concurrency ceiling for auto-scaling. The system adjusts the active concurrency between 1\nand this value based on rate-limit feedback. Only applied when `autoRecoverRateLimitErrors`\nis enabled on the connection. The same licensed maximum applies as for `concurrencyLevel`.","minimum":1,"maximum":50,"default":5}}},"JDBC":{"type":"object","description":"Configuration for JDBC (Java Database Connectivity) connections. Used when the connection\ntype is \"jdbc\". Provides access through Java JDBC drivers to databases not covered by the\nrdbms type — such as NetSuite SuiteAnalytics, Databricks, DB2, and Workday. The driver runs\non a Celigo on-premise Agent, so most jdbc connections need a connection-level _agentId.","required":["type"],"properties":{"type":{"type":"string","enum":["agent","netsuitejdbc","databricks","oracle:thin","sqlserver","activedirectory","db2","workday"],"description":"JDBC driver/connection type. Selects which JDBC driver is used and determines\nthe required fields. Most JDBC connections require a Celigo on-premise Agent."},"version":{"type":"string","description":"JDBC driver version. Used for driver compatibility when multiple versions are available."},"host":{"type":"string","description":"Database server hostname or IP address.\nFor NetSuite JDBC, use the SuiteAnalytics Connect hostname\n(e.g., \"account-id.connect.api.netsuite.com\").\n"},"port":{"type":"number","description":"Database server port number. Default varies by driver type."},"database":{"type":"string","description":"Database or catalog name. For Oracle, use the serviceName field instead.\n"},"user":{"type":"string","description":"Database username for authentication."},"password":{"type":"string","description":"Database password (encrypted at rest).","writeOnly":true},"serviceName":{"type":"string","description":"Oracle service name. Used instead of the database field for Oracle JDBC connections.\nThis is the TNS service name or pluggable database (PDB) service name.\n"},"authType":{"type":"string","enum":["customjdbc","wallet"],"description":"Authentication method for the JDBC connection. Defaults to customjdbc (username/password).\nUse wallet for Oracle Wallet authentication with the wallet field."},"wallet":{"type":"string","description":"Oracle Wallet file contents (encrypted at rest).\nRequired when authType is \"wallet\". Contains the auto-login wallet (cwallet.sso)\nwith encrypted credentials for passwordless Oracle authentication.\n","writeOnly":true},"driverPath":{"type":"string","description":"File path to the JDBC driver JAR on the Celigo Agent.\nRequired when type is \"agent\" (generic JDBC).\nThe driver must be deployed on the agent before creating the connection.\n"},"properties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"JDBC connection property name (driver-specific)."},"value":{"type":"string","description":"JDBC connection property value."}}},"description":"Additional JDBC connection properties as name/value pairs.\nThese are passed directly to the JDBC driver as connection properties.\nUse for driver-specific settings like SSL mode, connection timeout,\napplication name, etc.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent database connections.\nJDBC connections often run through a single Agent, so keep this value\nconservative to avoid overwhelming the Agent or database.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts the number of\nconcurrent connections between 1 and this value based on performance feedback.\n","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"type":{"const":"db2"}},"required":["type"]},"then":{"required":["host","user","password","database","port","properties"]},"else":{"if":{"properties":{"type":{"const":"oracle:thin"}},"required":["type"]},"then":{"required":["user","password","authType"],"if":{"properties":{"authType":{"const":"wallet"}},"required":["authType"]},"then":{"required":["wallet","serviceName"]},"else":{"required":["host"]}},"else":{"if":{"properties":{"type":{"const":"activedirectory"}},"required":["type"]},"then":{"required":["host","port","user","password","properties"]},"else":{"if":{"properties":{"type":{"const":"netsuitejdbc"}},"required":["type"]},"then":{"required":["host","user","properties"]},"else":{"if":{"properties":{"type":{"const":"agent"}},"required":["type"]},"then":{"required":["host","driverPath"]},"else":{"if":{"properties":{"type":{"const":"workday"}},"required":["type"]},"then":{"required":["host","user","password","properties"]},"else":{"if":{"properties":{"type":{"const":"databricks"}},"required":["type"]},"then":{"required":["host"]}}}}}}}},"VAN":{"type":"object","description":"Configuration for VAN (Value-Added Network) connections. Used when the connection type is \"van\".\nA VAN connection exchanges EDI documents through a managed network mailbox; outbound documents are\nposted to the mailbox and inbound documents are picked up from it, addressed by the connection's AS2 identifier.","properties":{"as2Id":{"type":"string","description":"AS2 identifier for this VAN station — the \"From\" identifier on outbound documents and the \"To\"\nidentifier on inbound. Must be unique across all integrator.io VAN connections; a duplicate fails\nthe create. Set once when the connection is created and cannot be changed afterward (writes on update\nare ignored). Omit it to have the network assign one automatically."},"mailboxId":{"type":"number","readOnly":true,"description":"Numeric mailbox identifier assigned by the VAN provider when the connection is provisioned.\nServer-assigned and not writable — values sent on create or update are ignored."},"contentBasedFlowRouter":{"type":"object","description":"Routes inbound documents to different flows based on message content, for a connection shared across\nmultiple flows. The named function in the referenced script inspects each incoming document and returns\nthe flow to run. Omit to disable content-based routing.","properties":{"function":{"type":"string","description":"Function in the referenced script that returns the target flow for each inbound document."},"_scriptId":{"type":"string","format":"objectId","description":"ID of the script resource that contains the routing function. Must reference an existing script; an unknown ID fails the request with 422 `invalid_ref`."}}}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper connections. Used when the connection type is \"wrapper\". A wrapper\nis a fully custom connector implemented in server-side JavaScript on a Celigo Stack\n(referenced by _stackId) — use it when the target API needs\nnon-standard authentication or logic that HTTP connections can't express. Connection-specific\nvalues go in the encrypted/unencrypted fields, which the wrapper code reads at runtime.","required":["pingFunction"],"properties":{"pingFunction":{"type":"string","description":"Name of the JavaScript function on the Stack that tests connection health, invoked when\n\"Test Connection\" is clicked. It should verify the credentials are valid and the target\nsystem is reachable."},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive configuration values.\nThese values are accessible to the wrapper code on the Stack at runtime.\nField definitions are specified in unencryptedFields.\n"},"unencryptedFields":{"type":"array","description":"Metadata defining the unencrypted custom fields on this connection.","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the unencrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip text shown next to the field in the UI."},"type":{"type":"string","description":"Optional, legacy field-type hint. The wrapper form ignores it — it always renders these\ncustom fields as text inputs — so it is rarely set."}}}},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for sensitive configuration values (API keys, passwords, etc.).\nSent as an object of field-name/value pairs; values are encrypted at rest and decrypted\nonly on the Stack at runtime. Returned as the masked string `\"******\"` on responses.\nField definitions are specified in encryptedFields.\n"},"encryptedFields":{"type":"array","description":"Metadata defining the encrypted custom fields on this connection.","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the encrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip text shown next to the field in the UI."},"type":{"type":"string","description":"Optional, legacy field-type hint. The wrapper form ignores it — it always renders these\ncustom fields as text inputs (masked) — so it is rarely set."}}}},"_stackId":{"type":"string","format":"objectId","description":"Reference to the Celigo Stack whose server-side JavaScript implements this connection."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent operations through this wrapper connection.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on performance feedback.\n","minimum":1,"maximum":50}}},"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/apis/{_id}/connections":{"get":{"operationId":"listApiConnections","tags":["APIs"],"summary":"List connections an API depends on","description":"Returns the connections referenced by the export and import steps in `builder.routers`,\nincluding connections a nested Tool step supplies through its overrides. Each connection\nappears once even when several steps share it. Use this to see which systems an API talks\nto before cloning it or calling `PUT /v1/apis/{_id}/replaceConnection`.\n\nCallers with manage access to the API's integration receive full Connection objects;\ncallers with monitor-only access receive a reduced representation (`_id`, `name`,\n`description`, `type`, and the connector or database type under the adaptor key) without\nendpoint or credential fields. Script-mode APIs have no steps and return an empty array.","parameters":[{"name":"_id","in":"path","required":true,"description":"API id.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Connections referenced by the API's steps. Empty array when the API has no steps\nor none of them use a connection.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Connection"}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Replace a connection across an API

> Repoints every export and import step in \`builder.routers\` that uses \`\_connectionId\`\
> to \`\_newConnectionId\`, saving each step resource in place, and returns how many steps\
> changed. Use it instead of per-resource PUTs when rotating credentials or promoting an\
> API between environments; \`GET /v1/apis/{\_id}/connections\` shows which connections the\
> API references before and after.\
> \
> Each affected step is re-validated against the replacement connection before anything\
> is saved, so a connection of an incompatible type (an FTP connection for an HTTP lookup,\
> for example) fails the whole request with \`422\` carrying one validation error per\
> affected step and leaves every step unchanged. A request whose \`\_connectionId\` matches\
> no step succeeds with \`replacedNodeCount\` 0. Script-mode APIs have no steps and always\
> return 0.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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":{"ApiReplaceConnectionRequest":{"type":"object","description":"Request body to swap one connection for another on every export and import step\nof a builder-mode API. Both ids must be well-formed; the replacement connection must\nexist in the account and satisfy each affected step's adaptor validation.","required":["_connectionId","_newConnectionId"],"properties":{"_connectionId":{"type":"string","format":"objectId","description":"Connection currently referenced by the API's steps. Steps that reference a\ndifferent connection are left untouched."},"_newConnectionId":{"type":"string","format":"objectId","description":"Connection to reference instead. Must be usable by every matching step — an\nHTTP export cannot be repointed to an FTP connection, for example."}}},"ApiReplaceConnectionResponse":{"type":"object","description":"Outcome of a connection replacement on a builder-mode API.","required":["replacedNodeCount"],"properties":{"replacedNodeCount":{"type":"integer","minimum":0,"description":"Number of export and import steps that referenced `_connectionId` and were\nsaved with `_newConnectionId`. Zero means no step used the connection and\nnothing changed."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/replaceConnection":{"put":{"operationId":"replaceConnectionOnApi","tags":["APIs"],"summary":"Replace a connection across an API","description":"Repoints every export and import step in `builder.routers` that uses `_connectionId`\nto `_newConnectionId`, saving each step resource in place, and returns how many steps\nchanged. Use it instead of per-resource PUTs when rotating credentials or promoting an\nAPI between environments; `GET /v1/apis/{_id}/connections` shows which connections the\nAPI references before and after.\n\nEach affected step is re-validated against the replacement connection before anything\nis saved, so a connection of an incompatible type (an FTP connection for an HTTP lookup,\nfor example) fails the whole request with `422` carrying one validation error per\naffected step and leaves every step unchanged. A request whose `_connectionId` matches\nno step succeeds with `replacedNodeCount` 0. Script-mode APIs have no steps and always\nreturn 0.","parameters":[{"name":"_id","in":"path","required":true,"description":"API id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiReplaceConnectionRequest"}}}},"responses":{"200":{"description":"Matching steps now reference the new connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiReplaceConnectionResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Test-run an API

> Executes the API once in a sandboxed test harness without invoking its public endpoint, and\
> returns the job tree produced by the run. Use this to validate a builder-mode API's request\
> parsing, routing, and response mapping before exposing it externally.\
> \
> The response carries a \`metadata\` map keyed by step id (each value is the ordered list of\
> stage names that ran for that step), the parent \`flowJob\`, and the per-step \`childJobs\[]\`.\
> The response the run selected appears in \`metadata\` too, keyed by its \`id\` (\`success\`,\
> \`fail\`, or a custom response's \`id\`). Inspect a specific step's stages with\
> \`GET /v1/apis/{\_id}/test/run/{runId}/{\_stepId}\`, where \`runId\` is the parent \`flowJob.\_id\`.\
> \
> Test-run invocations do \*\*not\*\* surface in \`GET /v1/apis/{\_id}/logs\`.\
> \
> A test run is not free of outside calls: a lookup export with no saved \`mockOutput\` calls\
> its source live, and the run then saves that response on the export as its \`mockOutput\`\
> (the export's \`lastModified\` changes). Every later test run that uses the export, from any\
> API or Tool and whatever its request, answers that lookup from the saved \`mockOutput\`\
> instead of calling the source: the lookup's \`request\` stage shows the request rendered\
> from the new record, and its \`response\` stage holds the saved records. Remove \`mockOutput\`\
> from the export to call the source again. Real calls to the API don't read it. Imports never\
> send; each returns its saved \`mockResponse\`, or a placeholder response when none is saved\
> (see \`mockResponse\` on imports).\
> \
> Test runs never paginate, whatever \`pagination.enabled\` says: the captured success\
> response carries no \`pagination\` object, and a \`Celigo-Next-Cursor\` entry in\
> \`mockRequest.headers\` is not validated — a malformed value does not fail the run.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/apis/{_id}/test/run":{"post":{"operationId":"testRunApi","tags":["APIs"],"summary":"Test-run an API","description":"Executes the API once in a sandboxed test harness without invoking its public endpoint, and\nreturns the job tree produced by the run. Use this to validate a builder-mode API's request\nparsing, routing, and response mapping before exposing it externally.\n\nThe response carries a `metadata` map keyed by step id (each value is the ordered list of\nstage names that ran for that step), the parent `flowJob`, and the per-step `childJobs[]`.\nThe response the run selected appears in `metadata` too, keyed by its `id` (`success`,\n`fail`, or a custom response's `id`). Inspect a specific step's stages with\n`GET /v1/apis/{_id}/test/run/{runId}/{_stepId}`, where `runId` is the parent `flowJob._id`.\n\nTest-run invocations do **not** surface in `GET /v1/apis/{_id}/logs`.\n\nA test run is not free of outside calls: a lookup export with no saved `mockOutput` calls\nits source live, and the run then saves that response on the export as its `mockOutput`\n(the export's `lastModified` changes). Every later test run that uses the export, from any\nAPI or Tool and whatever its request, answers that lookup from the saved `mockOutput`\ninstead of calling the source: the lookup's `request` stage shows the request rendered\nfrom the new record, and its `response` stage holds the saved records. Remove `mockOutput`\nfrom the export to call the source again. Real calls to the API don't read it. Imports never\nsend; each returns its saved `mockResponse`, or a placeholder response when none is saved\n(see `mockResponse` on imports).\n\nTest runs never paginate, whatever `pagination.enabled` says: the captured success\nresponse carries no `pagination` object, and a `Celigo-Next-Cursor` entry in\n`mockRequest.headers` is not validated — a malformed value does not fail the run.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"Optional test request for the run. The saved\n`builder.request.mockRequest` is never replayed: when the body is\nempty, omitted, or has no `mockRequest`, the first step receives\nan empty record.","properties":{"mockRequest":{"type":"object","description":"The simulated request for this run. Send the saved\n`builder.request.mockRequest` here to test with it.","properties":{"body":{"type":"object","description":"Request body for the simulated call. Only the body reaches\nthe record the steps see. Must be a JSON object: an array\nis refused with 400 \"Mock request body should be a plain\nobject.\""},"pathParams":{"type":"object","description":"Path parameter values for the simulated call."},"queryParams":{"type":"object","description":"Query parameter values for the simulated call."},"headers":{"type":"object","description":"Request headers for the simulated call."}}}},"additionalProperties":true}}}},"responses":{"200":{"description":"The job tree produced by the test run.","content":{"application/json":{"schema":{"type":"object","properties":{"metadata":{"type":"object","description":"Map keyed by step id; each value is the ordered list of stage names that ran for\nthat step. The selected response is one of the keys (`success`, `fail`, or a\ncustom response's `id`), so it names the response the run returned.","additionalProperties":{"type":"array","items":{"type":"string"}}},"flowJob":{"type":"object","description":"The parent job for the test run. Its `_id` is the `runId`."},"childJobs":{"type":"array","description":"Per-step child jobs produced during the run.","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get a step's stages from an API test run

> Returns the per-stage execution detail for a single step of a completed API test run. \`runId\`\
> is the parent \`flowJob.\_id\` returned by \`POST /v1/apis/{\_id}/test/run\`, and \`\_stepId\` is the\
> step id surfaced in that run's \`metadata\` map.\
> \
> Each entry in \`stages\[]\` carries the stage \`name\` (e.g. \`request\`, \`parse\`, \`router\`) plus its\
> \`input\`, \`output\`, and \`errors\`. Stages that did not produce data for a given direction return\
> \`null\` for that field. Top-level \`errors\` aggregates step-level errors.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/apis/{_id}/test/run/{runId}/{_stepId}":{"get":{"operationId":"getApiTestRunStep","tags":["APIs"],"summary":"Get a step's stages from an API test run","description":"Returns the per-stage execution detail for a single step of a completed API test run. `runId`\nis the parent `flowJob._id` returned by `POST /v1/apis/{_id}/test/run`, and `_stepId` is the\nstep id surfaced in that run's `metadata` map.\n\nEach entry in `stages[]` carries the stage `name` (e.g. `request`, `parse`, `router`) plus its\n`input`, `output`, and `errors`. Stages that did not produce data for a given direction return\n`null` for that field. Top-level `errors` aggregates step-level errors.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"runId","in":"path","required":true,"description":"The parent job id (`flowJob._id`) returned by the test-run request.","schema":{"type":"string"}},{"name":"_stepId","in":"path","required":true,"description":"The step id, as surfaced in the test run's `metadata` map.","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-stage execution detail for the requested step.","content":{"application/json":{"schema":{"type":"object","properties":{"stages":{"type":"array","description":"Ordered stages that ran for this step.","items":{"type":"object","properties":{"name":{"type":"string","description":"Stage name (e.g. `request`, `parse`, `router`)."},"errors":{"description":"Stage-level errors, or `null` when none."},"input":{"description":"Input records the stage received, or `null`."},"output":{"description":"Output records the stage produced, or `null`."}}}},"errors":{"type":"array","description":"Aggregated step-level errors.","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get request/response captures for an API test-run step

> Returns the request/response captures recorded for a single export or import step of an API\
> test run. \`runId\` is the parent \`flowJob.\_id\` from \`POST /v1/apis/{\_id}/test/run\`, and\
> \`\_stepId\` is the step id from that run's \`metadata\` map.\
> \
> Each entry in \`requests\[]\` is a summary identified by an opaque \`key\`; fetch the full decoded\
> request/response envelope with \`GET /v1/apis/{\_id}/{\_stepId}/requests/{key}\`. A step id that\
> is not an export or import (such as a router) returns a 400 \`invalid\_ref\`, and a step that\
> captured no request/response data returns a 404 \`req\_res\_logs\_not\_found\`.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/apis/{_id}/test/run/{runId}/{_stepId}/logs/requestAndResponse":{"get":{"operationId":"getApiTestRunStepLogs","tags":["APIs"],"summary":"Get request/response captures for an API test-run step","description":"Returns the request/response captures recorded for a single export or import step of an API\ntest run. `runId` is the parent `flowJob._id` from `POST /v1/apis/{_id}/test/run`, and\n`_stepId` is the step id from that run's `metadata` map.\n\nEach entry in `requests[]` is a summary identified by an opaque `key`; fetch the full decoded\nrequest/response envelope with `GET /v1/apis/{_id}/{_stepId}/requests/{key}`. A step id that\nis not an export or import (such as a router) returns a 400 `invalid_ref`, and a step that\ncaptured no request/response data returns a 404 `req_res_logs_not_found`.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"runId","in":"path","required":true,"description":"The parent job id (`flowJob._id`) returned by the test-run request.","schema":{"type":"string"}},{"name":"_stepId","in":"path","required":true,"description":"The step id, as surfaced in the test run's `metadata` map. Must be an export or import step.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request captures recorded for the step.","content":{"application/json":{"schema":{"type":"object","properties":{"requests":{"type":"array","description":"Captured request summaries for the step.","items":{"type":"object","properties":{"key":{"type":"string","description":"Opaque key for the capture. Resolve the full decoded request/response with\n`GET /v1/apis/{_id}/{_stepId}/requests/{key}`."},"time":{"type":"integer","description":"Capture time, epoch milliseconds."},"method":{"type":"string","description":"HTTP method of the captured request, or `undefined` when not applicable."},"statusCode":{"type":"string","description":"Response status code, as a string."},"stage":{"type":"string","description":"The stage that produced the capture (e.g. `import`)."}}}}}}}}},"400":{"description":"The `_stepId` does not resolve to an export or import step (for example, a router step\nor a malformed id). Use a step id that ran an outbound request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"No request/response data is stored for the requested step — it captured nothing, or the\nrun/step id didn't resolve.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## List captured requests for an API step

> Returns the set of requests captured for a single step of an API. \`\_stepId\` identifies the\
> step within the API's configuration. Each entry in \`requests\[]\` is a captured request summary;\
> follow up with \`GET /v1/apis/{\_id}/{\_stepId}/requests/{key}\` to retrieve one entry in full.\
> \
> An empty \`requests\[]\` simply means nothing is currently stored for this step.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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/apis/{_id}/{_stepId}/requests":{"get":{"operationId":"listApiStepRequests","tags":["APIs"],"summary":"List captured requests for an API step","description":"Returns the set of requests captured for a single step of an API. `_stepId` identifies the\nstep within the API's configuration. Each entry in `requests[]` is a captured request summary;\nfollow up with `GET /v1/apis/{_id}/{_stepId}/requests/{key}` to retrieve one entry in full.\n\nAn empty `requests[]` simply means nothing is currently stored for this step.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"The step id within the API's configuration.","schema":{"type":"string"}}],"responses":{"200":{"description":"Captured requests for the step. `requests[]` is empty when nothing is stored.","content":{"application/json":{"schema":{"type":"object","properties":{"requests":{"type":"array","description":"Captured request entries for this step.","items":{"type":"object"}}}}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get one captured request for an API step by key

> Returns the full captured request/response envelope for one entry of an API step, looked up by\
> the opaque \`key\` values surfaced in \`GET /v1/apis/{\_id}/{\_stepId}/requests\`. Matches the exact\
> entry whose key is provided — there is no partial-match query on this endpoint.\
> \
> Use the \`key\` exactly as returned by the parent listing; do not construct one manually. A 404\
> means the key has expired from retention or was never captured.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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/apis/{_id}/{_stepId}/requests/{key}":{"get":{"operationId":"getApiStepRequest","tags":["APIs"],"summary":"Get one captured request for an API step by key","description":"Returns the full captured request/response envelope for one entry of an API step, looked up by\nthe opaque `key` values surfaced in `GET /v1/apis/{_id}/{_stepId}/requests`. Matches the exact\nentry whose key is provided — there is no partial-match query on this endpoint.\n\nUse the `key` exactly as returned by the parent listing; do not construct one manually. A 404\nmeans the key has expired from retention or was never captured.","parameters":[{"name":"_id","in":"path","required":true,"description":"The API id.","schema":{"type":"string","format":"objectId"}},{"name":"_stepId","in":"path","required":true,"description":"The step id within the API's configuration.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Opaque request key from the parent `GET /v1/apis/{_id}/{_stepId}/requests` listing. Use the\n`key` exactly as returned; do not construct one manually.","schema":{"type":"string"}}],"responses":{"200":{"description":"The full captured request/response envelope for the entry.","content":{"application/json":{"schema":{"type":"object","description":"Decoded request/response envelope for the captured entry."}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Clone an API

> Clones a builder-mode API along with the resources it depends on (such as its\
> backing import) and returns a manifest of every resource created.\
> \
> The request body is required: \`version\` must be supplied, and the cloned API's\
> combination of \`version\`, \`method\`, and \`relativeURI\` must be unique. Reusing all\
> three returns a 422 \`clone\_api\_already\_exists\`. Pass \`\_integrationId\` to create the\
> clone inside an integration — when omitted, the clone is created standalone rather\
> than inheriting the source API's integration. Add \`\_apiGroupingId\` to file the clone\
> under one of that integration's \`apiGroupings\`.\
> \
> Only \*\*builder-type\*\* APIs can be cloned — cloning any other API type returns a 400\
> \`clone\_not\_supported\`.\
> \
> To check for a version/method/relativeURI conflict without creating anything, call\
> \`POST /v1/apis/{\_id}/clone/validate\` first.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/apis/{_id}/clone":{"post":{"operationId":"cloneApi","tags":["APIs"],"summary":"Clone an API","description":"Clones a builder-mode API along with the resources it depends on (such as its\nbacking import) and returns a manifest of every resource created.\n\nThe request body is required: `version` must be supplied, and the cloned API's\ncombination of `version`, `method`, and `relativeURI` must be unique. Reusing all\nthree returns a 422 `clone_api_already_exists`. Pass `_integrationId` to create the\nclone inside an integration — when omitted, the clone is created standalone rather\nthan inheriting the source API's integration. Add `_apiGroupingId` to file the clone\nunder one of that integration's `apiGroupings`.\n\nOnly **builder-type** APIs can be cloned — cloning any other API type returns a 400\n`clone_not_supported`.\n\nTo check for a version/method/relativeURI conflict without creating anything, call\n`POST /v1/apis/{_id}/clone/validate` first.","parameters":[{"name":"_id","in":"path","required":true,"description":"The id of the API to clone.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["version"],"properties":{"version":{"type":"string","description":"Version identifier for the cloned API. The cloned API's combination of\n`version`, `method`, and `relativeURI` must be unique — reusing all three\nreturns a 422 `clone_api_already_exists`."},"name":{"type":"string","description":"Name for the cloned API. Defaults to a copy of the source API's name when omitted."},"_integrationId":{"type":"string","format":"objectId","description":"Integration the cloned API is created in. When omitted, the clone is created\nstandalone — it does not inherit the source API's integration."},"_apiGroupingId":{"type":["string","null"],"format":"objectId","description":"Grouping inside the target integration that the clone is filed under; `null`\nor omitted leaves it ungrouped. Honored only together with `_integrationId` —\nsent without it, the clone is created standalone and the grouping is dropped\nsilently. A grouping that belongs to a different integration fails the clone\nwith 422 `apigrouping_not_belong` and nothing is created."}}}}}},"responses":{"201":{"description":"The clone was created. Returns a manifest of every resource the clone created —\nthe new API plus any dependencies it copied (imports, scripts).","content":{"application/json":{"schema":{"type":"array","description":"Manifest of resources created by the clone.","items":{"type":"object","properties":{"model":{"type":"string","description":"Model name of the created resource (e.g. `Api`, `Import`)."},"_id":{"type":"string","format":"objectId","description":"Unique id of the created resource."}}}}}}},"400":{"description":"The request was rejected. Common causes: the body omits the required `version`\nfield (`required_field_missing`), or the target API is not a builder-type API\n(`clone_not_supported` — only builder APIs can be cloned).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"An API with the same `version`, `method`, and `relativeURI` already exists — clone\nwith a different `version` (or change the method/URI) to create a distinct API — or\n`_apiGroupingId` is not one of the target integration's `apiGroupings`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Validate an API clone

> Dry-run check for \`POST /v1/apis/{\_id}/clone\`. Verifies that cloning the\
> API to the target \`version\` would not collide with an existing API route\
> — the clone keeps the source API's \`method\` and \`relativeURI\`, so the\
> target \`version\` + \`method\` + \`relativeURI\` combination must not conflict\
> with an API that is already registered in the account. Nothing is created\
> or modified.\
> \
> Returns \`canClone: true\` when the route is free, \`false\` when it\
> conflicts — pick a different \`version\` before calling\
> \`POST /v1/apis/{\_id}/clone\`. Only \*\*builder-type\*\* APIs can be validated;\
> a script-type API returns 404, the same as an unknown id.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/apis/{_id}/clone/validate":{"post":{"operationId":"validateApiClone","tags":["APIs"],"summary":"Validate an API clone","description":"Dry-run check for `POST /v1/apis/{_id}/clone`. Verifies that cloning the\nAPI to the target `version` would not collide with an existing API route\n— the clone keeps the source API's `method` and `relativeURI`, so the\ntarget `version` + `method` + `relativeURI` combination must not conflict\nwith an API that is already registered in the account. Nothing is created\nor modified.\n\nReturns `canClone: true` when the route is free, `false` when it\nconflicts — pick a different `version` before calling\n`POST /v1/apis/{_id}/clone`. Only **builder-type** APIs can be validated;\na script-type API returns 404, the same as an unknown id.","parameters":[{"name":"_id","in":"path","required":true,"description":"The id of the API to validate cloning for.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["version"],"properties":{"version":{"type":"string","description":"Version identifier the clone would be created under. Omitting\nit returns a 400 `required_field_missing`."}}}}}},"responses":{"200":{"description":"Validation result. Returned for both outcomes — check `canClone`.","content":{"application/json":{"schema":{"type":"object","properties":{"canClone":{"type":"boolean","description":"When true, the target `version` + `method` + `relativeURI`\nroute is free and the clone can be created. When false, the\nroute conflicts with an existing API — choose a different\n`version`."}}}}}},"400":{"description":"The body omits the required `version` field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"The API does not exist, is not visible to the caller, or is not a\nbuilder-type API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Get a downloadable template for an API

> Packages a builder-mode API as an installable template and returns a\
> signed S3 URL where the template \`.zip\` can be downloaded. The URL is\
> pre-signed and short-lived (approximately 15 minutes), so fetch the file\
> promptly; call the endpoint again for a fresh URL.\
> \
> The \`.zip\` contains the API definition plus every resource it references\
> — imports, exports, connections, and scripts — grouped into one folder\
> per resource type, with an \`integration.json\` manifest at the root.\
> \
> Only \*\*builder-type\*\* APIs can be exported — requesting a script-type\
> API returns 404, the same as an unknown id. Requires the\
> \`create:api:template\` permission.

```json
{"openapi":"3.2.0","info":{"title":"APIs","version":"1.0.0"},"tags":[{"name":"APIs","description":"APIs expose integration logic as HTTP endpoints that external systems can invoke.\n\nTwo modes:\n- **Builder** — visual configuration with request/response mapping, routing, and transformations\n- **Script** — custom JavaScript handler function for full control\n\nEach API gets a public URL: `https://api.integrator.io/apis/{version}{relativeURI}`\n\n## API schema\n\n{% openapi-schemas spec=\"api\" schemas=\"API\" 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"]}}}}},"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/apis/{_id}/template":{"get":{"operationId":"getApiTemplate","tags":["APIs"],"summary":"Get a downloadable template for an API","description":"Packages a builder-mode API as an installable template and returns a\nsigned S3 URL where the template `.zip` can be downloaded. The URL is\npre-signed and short-lived (approximately 15 minutes), so fetch the file\npromptly; call the endpoint again for a fresh URL.\n\nThe `.zip` contains the API definition plus every resource it references\n— imports, exports, connections, and scripts — grouped into one folder\nper resource type, with an `integration.json` manifest at the root.\n\nOnly **builder-type** APIs can be exported — requesting a script-type\nAPI returns 404, the same as an unknown id. Requires the\n`create:api:template` permission.","parameters":[{"name":"_id","in":"path","required":true,"description":"The id of the API to export.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Signed download URL for the API template zip.","content":{"application/json":{"schema":{"type":"object","properties":{"signedURL":{"type":"string","format":"uri","description":"Pre-signed, short-lived S3 URL to download the template `.zip`."},"key":{"type":"string","description":"S3 object key for the generated template `.zip`, named `<apiId>.zip`."}}}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"The API does not exist, is not visible to the caller, or is not a\nbuilder-type API (script-type APIs cannot be exported as templates).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```
