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

# Exports

Exports retrieve data from source systems — on a schedule, in delta mode, in real time, on demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass each page to downstream flow steps. Depending on configuration, an export surfaces in the Flow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.

### Export schema

## The Export object

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"components":{"schemas":{"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}}}}}
````

## List exports

> Returns a list of all exports configured in the account.\
> If no exports exist in the account, a 204 response with no body will be returned.<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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":{"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}}},"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/exports":{"get":{"summary":"List exports","description":"Returns a list of all exports configured in the account.\nIf no exports exist in the account, a 204 response with no body will be returned.\n","operationId":"listExports","tags":["Exports"],"parameters":[{"name":"externalId","in":"query","description":"Filter to exports matching this exact external identifier.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of exports to return per page.","schema":{"type":"integer","minimum":1}},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"Successfully retrieved list of exports","headers":{"Link":{"description":"RFC-5988 pagination links. When more pages remain, includes a `<...>; rel=\"next\"` entry;\nabsent on the final page.\n","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Export"}}}}},"204":{"description":"No exports exist in the account"},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
````

## Create an export

> Creates a new export configuration that can be used to retrieve data from applications\
> or external sources.<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Fields that can be sent when creating or updating an export. Set the adaptor-specific\nconfiguration object matching `adaptorType`, and the mode-specific object matching `type`.\n`SimpleExport` (data-loader) is the exception — it needs no adaptor config object.","required":["name"],"allOf":[{"$ref":"#/components/schemas/ExportBase"}],"if":{"properties":{"adaptorType":{"const":"HTTPExport"}},"required":["adaptorType"]},"then":{"required":["http"]},"else":{"if":{"properties":{"adaptorType":{"const":"FTPExport"}},"required":["adaptorType"]},"then":{"required":["ftp"]},"else":{"if":{"properties":{"adaptorType":{"const":"AS2Export"}},"required":["adaptorType"]},"then":{"if":{"not":{"properties":{"type":{"const":"webhook"}},"required":["type"]}},"then":{"required":["file"]}},"else":{"if":{"properties":{"adaptorType":{"const":"S3Export"}},"required":["adaptorType"]},"then":{"required":["s3"]},"else":{"if":{"properties":{"adaptorType":{"const":"NetSuiteExport"}},"required":["adaptorType"]},"then":{"required":["netsuite"]},"else":{"if":{"properties":{"adaptorType":{"const":"NetSuiteHTTPExport"}},"required":["adaptorType"]},"then":{"required":["http","nsDomainType"]},"else":{"if":{"properties":{"adaptorType":{"const":"SalesforceExport"}},"required":["adaptorType"]},"then":{"required":["salesforce"]},"else":{"if":{"properties":{"adaptorType":{"const":"JDBCExport"}},"required":["adaptorType"]},"then":{"required":["jdbc"]},"else":{"if":{"properties":{"adaptorType":{"const":"RDBMSExport"}},"required":["adaptorType"]},"then":{"required":["rdbms"]},"else":{"if":{"properties":{"adaptorType":{"const":"MongodbExport"}},"required":["adaptorType"]},"then":{"required":["mongodb"]},"else":{"if":{"properties":{"adaptorType":{"const":"DynamodbExport"}},"required":["adaptorType"]},"then":{"required":["dynamodb"]},"else":{"if":{"properties":{"adaptorType":{"const":"WrapperExport"}},"required":["adaptorType"]},"then":{"required":["wrapper"]},"else":{"if":{"properties":{"adaptorType":{"const":"WebhookExport"}},"required":["adaptorType"]},"then":{"required":["webhook"]},"else":{"if":{"properties":{"adaptorType":{"const":"FileSystemExport"}},"required":["adaptorType"]},"then":{"required":["filesystem"]},"else":{"if":{"properties":{"adaptorType":{"const":"RESTExport"}},"required":["adaptorType"]},"then":{"required":["http"]}}}}}}}}}}}}}}}},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}},"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/exports":{"post":{"summary":"Create an export","description":"Creates a new export configuration that can be used to retrieve data from applications\nor external sources.\n","operationId":"createExport","tags":["Exports"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"201":{"description":"Export created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
````

## Get an export

> Returns the complete configuration of a specific export.<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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":{"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}},"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/exports/{_id}":{"get":{"summary":"Get an export","description":"Returns the complete configuration of a specific export.\n","operationId":"getExportById","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Export retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
````

## Update an export

> Updates an existing export with the provided configuration.\
> This is used for major updates to an export's structure or behavior.<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Fields that can be sent when creating or updating an export. Set the adaptor-specific\nconfiguration object matching `adaptorType`, and the mode-specific object matching `type`.\n`SimpleExport` (data-loader) is the exception — it needs no adaptor config object.","required":["name"],"allOf":[{"$ref":"#/components/schemas/ExportBase"}],"if":{"properties":{"adaptorType":{"const":"HTTPExport"}},"required":["adaptorType"]},"then":{"required":["http"]},"else":{"if":{"properties":{"adaptorType":{"const":"FTPExport"}},"required":["adaptorType"]},"then":{"required":["ftp"]},"else":{"if":{"properties":{"adaptorType":{"const":"AS2Export"}},"required":["adaptorType"]},"then":{"if":{"not":{"properties":{"type":{"const":"webhook"}},"required":["type"]}},"then":{"required":["file"]}},"else":{"if":{"properties":{"adaptorType":{"const":"S3Export"}},"required":["adaptorType"]},"then":{"required":["s3"]},"else":{"if":{"properties":{"adaptorType":{"const":"NetSuiteExport"}},"required":["adaptorType"]},"then":{"required":["netsuite"]},"else":{"if":{"properties":{"adaptorType":{"const":"NetSuiteHTTPExport"}},"required":["adaptorType"]},"then":{"required":["http","nsDomainType"]},"else":{"if":{"properties":{"adaptorType":{"const":"SalesforceExport"}},"required":["adaptorType"]},"then":{"required":["salesforce"]},"else":{"if":{"properties":{"adaptorType":{"const":"JDBCExport"}},"required":["adaptorType"]},"then":{"required":["jdbc"]},"else":{"if":{"properties":{"adaptorType":{"const":"RDBMSExport"}},"required":["adaptorType"]},"then":{"required":["rdbms"]},"else":{"if":{"properties":{"adaptorType":{"const":"MongodbExport"}},"required":["adaptorType"]},"then":{"required":["mongodb"]},"else":{"if":{"properties":{"adaptorType":{"const":"DynamodbExport"}},"required":["adaptorType"]},"then":{"required":["dynamodb"]},"else":{"if":{"properties":{"adaptorType":{"const":"WrapperExport"}},"required":["adaptorType"]},"then":{"required":["wrapper"]},"else":{"if":{"properties":{"adaptorType":{"const":"WebhookExport"}},"required":["adaptorType"]},"then":{"required":["webhook"]},"else":{"if":{"properties":{"adaptorType":{"const":"FileSystemExport"}},"required":["adaptorType"]},"then":{"required":["filesystem"]},"else":{"if":{"properties":{"adaptorType":{"const":"RESTExport"}},"required":["adaptorType"]},"then":{"required":["http"]}}}}}}}}}}}}}}}},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}},"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/exports/{_id}":{"put":{"summary":"Update an export","description":"Updates an existing export with the provided configuration.\nThis is used for major updates to an export's structure or behavior.\n","operationId":"updateExport","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"200":{"description":"Export updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
````

## Delete an export

> Deletes an export. The export is soft-deleted and retained in the recycle bin\
> for 30 days before permanent removal. If the export is currently in use by\
> any flows, those flows may fail until reconfigured.<br>

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-dependency-conflict":{"description":"The resource has dependents that must be deleted first. Each entry\nin the `errors` array names one blocking resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/exports/{_id}":{"delete":{"summary":"Delete an export","description":"Deletes an export. The export is soft-deleted and retained in the recycle bin\nfor 30 days before permanent removal. If the export is currently in use by\nany flows, those flows may fail until reconfigured.\n","operationId":"deleteExport","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Export deleted successfully"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-dependency-conflict"}}}}}}
```

## Patch an export

> Partially updates an export using a JSON Patch document (RFC 6902).\
> Only the \`replace\` operation is supported, and only on the following\
> whitelisted paths:\
> \
> \| Path | Description |\
> \|------|-------------|\
> \| \`/debugUntil\` | Debug logging expiry (ISO-8601, max 1 hour from now) |\
> \| \`/assistantMetadata\` | Assistant metadata object |\
> \
> All other paths are rejected with \`422\`.

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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/exports/{_id}":{"patch":{"summary":"Patch an export","description":"Partially updates an export using a JSON Patch document (RFC 6902).\nOnly the `replace` operation is supported, and only on the following\nwhitelisted paths:\n\n| Path | Description |\n|------|-------------|\n| `/debugUntil` | Debug logging expiry (ISO-8601, max 1 hour from now) |\n| `/assistantMetadata` | Assistant metadata object |\n\nAll other paths are rejected with `422`.","operationId":"patchExport","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonPatchRequest"}}}},"responses":{"204":{"description":"Export patched successfully"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Clone an export

> Creates a copy of an existing export.\
> Supports optionally remapping referenced connections (via connectionMap).<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"CloneRequest":{"type":"object","description":"Request body for cloning an export.","properties":{"name":{"type":"string","description":"Optional name for the cloned resource. If omitted, the server may generate a default clone name."},"connectionMap":{"type":"object","description":"Optional mapping of original connection ids to replacement connection ids.\nKeys are source connection ids on the original resource; values are target connection ids.\n","additionalProperties":{"type":"string"}}},"additionalProperties":true},"CloneResponse":{"description":"Response body for a clone operation. Some clone endpoints return the cloned resource, while others may return a list of related created resources.","oneOf":[{"$ref":"#/components/schemas/Export"},{"type":"array","items":{"type":"object","properties":{"model":{"type":"string","description":"Model name of the created resource (e.g., Flow, Export, Import)."},"_id":{"type":"string","format":"objectId","description":"Unique id of the created resource."},"name":{"type":"string","description":"Optional name of the created resource."}},"required":["_id"]}}]},"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}},"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/exports/{_id}/clone":{"post":{"summary":"Clone an export","description":"Creates a copy of an existing export.\nSupports optionally remapping referenced connections (via connectionMap).\n","operationId":"cloneExport","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export to clone","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneRequest"}}}},"responses":{"201":{"description":"Export cloned successfully. Returns a manifest of the resource the clone created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
````

## Replace connection on export present in a flow

> Replaces the connection used by an export in a flow and cancels any running jobs.\
> This is useful when migrating flows between environments or updating to newer connection versions.<br>

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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/exports/{_id}/replaceConnection":{"put":{"summary":"Replace connection on export present in a flow","description":"Replaces the connection used by an export in a flow and cancels any running jobs.\nThis is useful when migrating flows between environments or updating to newer connection versions.\n","operationId":"replaceConnectionOnExport","tags":["Exports"],"parameters":[{"name":"_id","in":"path","description":"The unique identifier of the export","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"_newConnectionId":{"type":"string","description":"The id of the new connection to be used"}},"required":["_newConnectionId"]}}}},"responses":{"204":{"description":"Successfully replaced connection on export"},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Preview the output of an export doc (no job created)

> Runs an export doc through the flow engine's preview pipeline and returns\
> the sample data it would have emitted, along with stage-by-stage\
> diagnostics and any errors encountered. \*\*No Job record is created\*\* and\
> no flow-level state is updated — this is a stateless preview.\
> \
> Body is a complete export document (the shape you would POST to\
> \`/v1/exports\`), typically without \`\_id\`. The CLI uses it for two\
> scenarios:\
> \- \`ora exports invoke\` with a doc on stdin → ad-hoc preview of a\
> &#x20; not-yet-saved export.\
> \- Agent-driven "preview + refine" loops where an LLM iterates on the\
> &#x20; export config and calls this endpoint to sample output each time.\
> \
> The scoped variant at\
> \`POST /v1/integrations/{\_integrationId}/flows/{\_flowId}/exports/preview\`\
> does the same thing but inherits flow + integration context (useful when\
> the export references flow-scoped settings). Prefer the unscoped variant\
> when previewing a standalone export.\
> \
> Use \`test.limit\` inside the body to cap the number of records\
> returned. Configuration errors in the export doc surface in the\
> \`errors\[]\` and \`stages\[].errors\[]\` arrays within a 200 response;\
> only structural validation failures (e.g. missing \`\_connectionId\`)\
> return 4xx.

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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":{"ExportPreviewResponse":{"type":"object","description":"Envelope returned by `POST /v1/exports/preview` (and the scoped\n`/v1/integrations/{_integrationId}/flows/{_flowId}/exports/preview`\nvariant). Carries per-stage diagnostics alongside the sampled records.","properties":{"data":{"type":"array","description":"Final sampled records produced by the preview — the output of the last\nstage. Identical in practice to the last `stages[].data` entry, exposed\nhere as a convenience for callers that only care about the end result.","items":{}},"dataURIs":{"type":"array","description":"URIs for any files produced by the preview (e.g. file-based exports\nwriting to cloud storage). Empty for non-file adaptors.","items":{"type":"string"}},"dataRecordTraceKeys":{"type":"array","description":"Trace keys for the records in this preview — one per record,\ncorrelating stage outputs to their source record.","items":{"type":"string"}},"stages":{"type":"array","description":"Ordered list of pipeline stages the preview traversed. The preview\nruns through parsing only — the export's transform, output filter,\nand preSavePage hook are NOT applied here (they run in flow\npreviews, test runs, and real runs). Observed stage names: `parse`\nalways; `request` and `raw` for HTTP exports; `group` when the\nexport groups records (grouped records are bare arrays of the\ngrouped rows). Each stage carries its `data[]` output and any\n`errors[]` raised at that stage.","items":{"type":"object","description":"One pipeline stage's diagnostic and output envelope.","properties":{"name":{"type":"string","description":"Stage identifier (e.g. `parse`, `request`, `raw`)."},"data":{"description":"Stage output. Shape varies — `raw` carries the source\nresponse, `parse` (and `group`) carry the extracted records.","oneOf":[{"title":"Array","type":"array","items":{}},{"title":"Object","type":"object","additionalProperties":true},{"title":"Null","type":"null"}]},"errors":{"type":["array","null"],"description":"Errors raised at this stage, or `null` when clean.","items":{"type":"object","additionalProperties":true}}}}},"errors":{"type":"array","description":"Top-level error aggregate — typically mirrors the first non-null\n`stages[].errors[]` entry. Often omitted entirely when the preview\nran clean; callers should treat `undefined` and `[]` as equivalent.","items":{"type":"object","additionalProperties":true}},"traceKeysDuplicate":{"type":"array","description":"Trace keys that collided during the preview — a diagnostic for\ntrace-key generation; rarely non-empty in practice.","items":{"type":"string"}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/exports/preview":{"post":{"operationId":"previewExport","tags":["Exports"],"summary":"Preview the output of an export doc (no job created)","description":"Runs an export doc through the flow engine's preview pipeline and returns\nthe sample data it would have emitted, along with stage-by-stage\ndiagnostics and any errors encountered. **No Job record is created** and\nno flow-level state is updated — this is a stateless preview.\n\nBody is a complete export document (the shape you would POST to\n`/v1/exports`), typically without `_id`. The CLI uses it for two\nscenarios:\n- `ora exports invoke` with a doc on stdin → ad-hoc preview of a\n  not-yet-saved export.\n- Agent-driven \"preview + refine\" loops where an LLM iterates on the\n  export config and calls this endpoint to sample output each time.\n\nThe scoped variant at\n`POST /v1/integrations/{_integrationId}/flows/{_flowId}/exports/preview`\ndoes the same thing but inherits flow + integration context (useful when\nthe export references flow-scoped settings). Prefer the unscoped variant\nwhen previewing a standalone export.\n\nUse `test.limit` inside the body to cap the number of records\nreturned. Configuration errors in the export doc surface in the\n`errors[]` and `stages[].errors[]` arrays within a 200 response;\nonly structural validation failures (e.g. missing `_connectionId`)\nreturn 4xx.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Full export document (mirror of `POST /v1/exports` body shape),\noptionally with `test.limit` to cap preview record count. Omit\n`_id` when previewing a not-yet-saved export.","additionalProperties":true}}}},"responses":{"200":{"description":"Preview envelope — always returned on valid-body calls. User-error in\nthe export config (handlebars template failures, runtime errors)\nsurfaces in `errors[]` and `stages[].errors[]`; inspect those before\ntrusting `stages[].data[]`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportPreviewResponse"}}}},"400":{"description":"The export type does not support preview. Virtual (unsaved) previews\nare rejected for `simple` and other virtual export types — only\nbuilder-style exports (e.g. HTTP, RDBMS) can be previewed via this\nendpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"description":"Structural validation failed — typically `missing_required_field`\nfor fields the preview pipeline needs before it can execute\n(e.g. `_connectionId`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Preview export data

> Preview export data from a specific export within a flow. This endpoint allows you to\
> preview the data that would be exported, including the exported data, URIs to the data\
> in the source app, and processing stages information.<br>

````json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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":{"PreviewRequest":{"type":"object","description":"Request body for previewing export data","allOf":[{"$ref":"#/components/schemas/Export"},{"type":"object","properties":{"postData":{"type":"object","description":"Additional data for the export preview","properties":{"currentExportDateTime":{"type":"string","description":"Current export date time (timestamp)"},"lastExportDateTime":{"type":"string","description":"Last export date time (timestamp)"}}}}}]},"Export":{"type":"object","required":["_id","name","adaptorType","createdAt","lastModified"],"description":"Export object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ExportBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"apim":{"$ref":"#/components/schemas/APIM"},"apiIdentifier":{"type":"string","readOnly":true,"description":"API identifier assigned to this export."},"asynchronous":{"type":"boolean","readOnly":true,"description":"Server-managed execution-mode flag set on creation; client values are ignored."},"__linkedLookupCacheIds":{"type":"array","readOnly":true,"description":"Lookup caches linked to this export, managed by the platform.","items":{"type":"string","format":"objectId"}},"_sourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the source resource this export was created from."},"_templateId":{"type":"string","format":"objectId","readOnly":true,"description":"Template this export was created from."},"draft":{"type":"boolean","readOnly":true,"description":"When true, this export is in draft state and has not been confirmed."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the draft version of this export expires."},"debugUntil":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp until which debug logging is enabled for this export."}}}]},"ExportBase":{"type":"object","description":"Writable export fields shared by the request and response schemas.","properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the export, shown in the flow builder, job history, and error logs.\nDescriptive, unique names indicating the data source and purpose make large accounts easier to manage."},"description":{"type":["string","null"],"description":"Free-text summary of what the export retrieves and why. Shown in the UI and available\nto AI agents for context; has no effect on execution.","maxLength":5120},"_connectionId":{"format":"objectId","type":["string","null"],"description":"Connection this export uses to reach the source system. The connection's type must be\ncompatible with the export's `adaptorType` (e.g. an `HTTPExport` needs an `http` connection;\n`NetSuiteExport` and `NetSuiteHTTPExport` both need a `netsuite` connection).\nServer-required unless `type` is `webhook` or `simple` (those receive data instead of fetching it)."},"adaptorType":{"type":"string","description":"Selects the adaptor technology that executes this export, which determines the compatible\nconnection types and which adaptor-specific configuration object must also be supplied\n(e.g. set `salesforce` when using `SalesforceExport`).","enum":["HTTPExport","FTPExport","AS2Export","S3Export","NetSuiteExport","NetSuiteHTTPExport","SalesforceExport","JDBCExport","RDBMSExport","MongodbExport","DynamodbExport","WrapperExport","SimpleExport","WebhookExport","FileSystemExport","RESTExport"]},"nsDomainType":{"type":"string","enum":["suitetalk","restlet"],"description":"Selects which NetSuite REST host a `NetSuiteHTTPExport` calls. The server derives the\nfull base URL from the connection's NetSuite account\n(`https://<account>.suitetalk.api.netsuite.com` or `https://<account>.restlets.api.netsuite.com`)\nand signs each request with the connection's token-based credentials, so `http.relativeURI`\ncarries the complete path starting at `/services/rest/...` or `/app/site/hosting/restlet.nl`.\nIgnored on other adaptor types."},"type":{"type":["string","null"],"description":"Operational mode of the export. When omitted, the export retrieves all available records —\nthe standard batch mode, which is also the right choice for parsing structured files\n(CSV/XML/JSON) into records. Each mode requires its matching configuration object\n(e.g. a `delta` object when `type` is `delta`); use `blob` only to transfer raw files\nwithout parsing their contents.","enum":["webhook","test","delta","once","tranlinedelta","simple","blob","distributed","stream","all"]},"pageSize":{"type":["integer","null"],"description":"Number of records per page streamed to downstream flow steps when the export is the\nflow's source step. Pages are additionally capped at 5 MB regardless of record count, so\nvery large records may produce smaller pages. The server does not validate the value.\nA lookup (`isLookup: true`) runs to completion and hands every result to the incoming\nrecord as one response, capped at 5 MB in total, so the value does not change how many\nresults a lookup returns; a result set larger than that belongs in a standalone export\nstep. In a test run or preview the value also caps the records fetched (default 20).","default":20},"dataURITemplate":{"type":"string","description":"Handlebars template that builds a link back to each record in the source application's UI\n(e.g. `https://my.salesforce.com/lightning/r/Contact/{{record.Id}}/view`). The resolved\nURL is stored with error records in job history so users can jump straight to the record."},"traceKeyTemplate":{"type":["string","null"],"description":"Handlebars template that overrides how each record's unique trace key is generated, used\nto track records through the flow and match retries to prior errors (e.g.\n`{{join \"_\" record.customerId record.orderId}}`). When omitted, the system picks a unique\nfield automatically. If a transform reshapes the data first, omit the `record.` prefix.\nTrace keys are capped at 256 characters; a longer key is stored truncated from the middle,\nkeeping the beginning and end of the value."},"skipRetries":{"type":"boolean","description":"When true, the platform does not retain the source data needed to retry failed records,\nreducing stored data at the cost of being unable to reprocess errors from this export.\nShown as \"Do not store retry data\" in the UI. Defaults to false."},"oneToMany":{"$ref":"#/components/schemas/OneToMany"},"pathToMany":{"$ref":"#/components/schemas/PathToMany"},"isLookup":{"type":"boolean","description":"When true, the export runs as a mid-flow lookup: it executes once per incoming record,\nusing the input record's fields to parameterize the request, and passes the results to\nsubsequent steps. When false, the export runs as a standalone data source. A lookup's\nresults are not paged through the flow: every page the adaptor fetches is merged into one\nresponse for the record, up to 5 MB, so `pageSize` does not limit or extend what a lookup\nreturns. A lookup that must return more than that is better modeled as a standalone\nexport step."},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"delta":{"$ref":"#/components/schemas/Delta"},"test":{"$ref":"#/components/schemas/Test"},"once":{"$ref":"#/components/schemas/Once"},"webhook":{"$ref":"#/components/schemas/Webhook"},"simple":{"$ref":"#/components/schemas/Simple"},"distributed":{"$ref":"#/components/schemas/Distributed"},"cdc":{"$ref":"#/components/schemas/Cdc"},"filesystem":{"$ref":"#/components/schemas/FileSystem"},"http":{"$ref":"#/components/schemas/Http"},"file":{"$ref":"#/components/schemas/File"},"salesforce":{"$ref":"#/components/schemas/Salesforce"},"as2":{"$ref":"#/components/schemas/AS2"},"dynamodb":{"$ref":"#/components/schemas/DynamoDB"},"ftp":{"$ref":"#/components/schemas/FTP"},"jdbc":{"$ref":"#/components/schemas/JDBC"},"mongodb":{"$ref":"#/components/schemas/MongoDB"},"netsuite":{"$ref":"#/components/schemas/NetSuite"},"rdbms":{"$ref":"#/components/schemas/RDBMS"},"s3":{"$ref":"#/components/schemas/S3"},"wrapper":{"$ref":"#/components/schemas/Wrapper"},"parsers":{"$ref":"#/components/schemas/Parsers"},"filter":{"description":"Filter applied to records immediately after they are retrieved from the source.\nRecords that match continue through the flow; records that don't are silently dropped.\nFilter expressions reference the exported record's own fields.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"inputFilter":{"description":"Filter applied to incoming records before a lookup export queries the external system.\nOnly matching input records trigger lookup calls; non-matching records pass through the\nstep unenriched, which cuts unnecessary API traffic. Only relevant when `isLookup` is true.","allOf":[{"$ref":"#/components/schemas/Filter"}]},"mappings":{"description":"Field mappings applied to each incoming record before a lookup HTTP request is made,\nreshaping the upstream record into the structure the lookup target API expects. Only\nsupported when `isLookup` is true and `adaptorType` is `HTTPExport` or\n`NetSuiteHTTPExport`; do not set it on source exports or other lookup adaptors.","allOf":[{"$ref":"#/components/schemas/Mappings"}]},"transform":{"description":"Transformation that reshapes records before they leave this step — source exports\ntransform the retrieved records, lookup exports transform the lookup results. Commonly\nused to flatten nested lookup responses (e.g. `results[0].id` → `id`); merging results\nback into source records is handled separately by the flow's response mapping.","allOf":[{"$ref":"#/components/schemas/Transform"}]},"hooks":{"type":"object","description":"Custom JavaScript hooks that run at fixed points in the export lifecycle for\ntransformations, validation, and filtering beyond what configuration alone can express.","properties":{"preSavePage":{"type":"object","description":"Hook that runs after each page of records is retrieved from the source but before it\nis sent to downstream steps. Commonly used to flatten structures, drop unwanted\nrecords, or add computed fields.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."},"_stackId":{"type":"string","format":"objectId","description":"Stack that hosts the hook logic, used instead of a script for stack-based deployments."},"configuration":{"type":"object","description":"Static parameters passed to the hook function at runtime, letting one script be\nreused across exports with different settings."}}}}},"settingsForm":{"$ref":"#/components/schemas/Form"},"settings":{"$ref":"#/components/schemas/Settings"},"mockOutput":{"$ref":"#/components/schemas/MockOutput"},"_ediProfileId":{"type":"string","format":"objectId","description":"EDI profile this export uses to parse incoming X12 or EDIFACT documents into structured\nJSON — it supplies the envelope qualifiers, delimiters, version, and validation rules.\nSet it when the export parses or validates EDI files; omit it otherwise. Accepted on the\nfile-reading exports — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"_postParseListenerId":{"type":"string","format":"objectId","description":"Webhook export invoked once per file after EDI parsing, on both success and failure\n(errors are included in the payload when parsing fails). Primarily used to send\nfunctional acknowledgements (997/999) to trading partners. Accepted on the file-reading\nexports that parse EDI — FTP, AS2, S3 and HTTP file mode (`http.type: \"file\"`)."},"externalId":{"type":["string","null"],"description":"External identifier for correlating the export with a record in another system."},"_integrationId":{"type":["string","null"],"format":"objectId","description":"Integration this export belongs to."},"_connectorId":{"type":"string","format":"objectId","description":"Connector this export was created from, set when the export is part of an installed integration app."},"unencrypted":{"type":"object","description":"Custom configuration values stored without encryption and returned in API responses."},"useTechAdaptorForm":{"type":"boolean","description":"When true, the UI presents the full technical adaptor form for this export instead of\nthe simplified assistant form."},"rawData":{"type":"string","description":"Key referencing the raw sample payload captured for preview and testing."},"preSave":{"$ref":"#/components/schemas/PreSave"},"assistant":{"type":"string","description":"Identifier for the connector assistant used to configure this export."},"assistantMetadata":{"type":["object","string"],"additionalProperties":true,"description":"Metadata associated with the connector assistant configuration."},"sampleData":{"type":["string","object","array","null"],"description":"Sample data payload used for previewing and testing the export."},"sampleHeaders":{"type":"array","description":"Sample HTTP headers used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value."}}}},"sampleQueryParams":{"type":"array","description":"Sample query parameters used for previewing and testing the export.","items":{"type":"object","properties":{"name":{"type":"string","description":"Query parameter name."},"value":{"type":"string","description":"Query parameter value."}}}}}},"OneToMany":{"type":"boolean","description":"When true, the step runs once per child record instead of once per incoming record.\n`pathToMany` names the array field that holds the children inside an object record; when\nthe incoming record is itself an array (grouped or row-based data), leave `pathToMany` blank\nand each element becomes a record. The fan-out is scoped to this step: afterwards the children\nare re-joined into the record's original shape — the object with its array, or the array of rows —\ncarrying any response-mapping enrichment, and that re-joined record is what the next step\nreceives. Not for locating records in an export's HTTP response; use\n`http.response.resourcePath` for that. Applies to steps that receive a record — imports and\nlookups (an export referenced as a page processor of a flow, API, or Tool). A standalone export\n(a flow's page generator) has no incoming record, so the fields are saved but have no effect on\nthe records it produces; to emit one record per array element from a standalone export, use a\n`hooks.preSavePage` script, or for a file-definition export make the repeating segment the\nrecord boundary in the definition's rules.\n","default":false},"PathToMany":{"type":"string","description":"Path to the array of child records inside an object record when `oneToMany` is true, in dot\nnotation (`items`, `lines.lineItems`). Leave blank when the incoming record is itself an array\n(grouped or row-based data) — each element is then a child record. A path that does not resolve\nto an array processes zero records and reports success. Read only on steps that receive a\nrecord (imports, lookup exports); on a standalone export it is saved and ignored — see `oneToMany`.\n"},"GroupBy":{"type":"array","description":"Specifies which fields to use for grouping records in the export results. When configured, records with\nthe same values in these fields will be grouped together and treated as a single record by downstream\nsteps in your flow.\n\nFor example:\n- Group sales orders by customer ID to process all orders for each customer together\n- Group journal entries by accounting period to consolidate related transactions\n- Group inventory items by location to process inventory by warehouse\n\nWhen grouping is used, the export's page size determines the maximum number of groups per page, not individual\nrecords. Note that effective grouping typically requires that records with the same group field values appear\ntogether in the export data.\n","items":{"type":"string"}},"Delta":{"type":"object","description":"Configures incremental exports that retrieve only records created or modified since the last\nsuccessful run. Required when the export's type is \"delta\"; omit for other export types.\nWhen no cutoff is supplied, the platform-managed last-successful-run timestamp (exposed as\n{{lastExportDateTime}}) is the lower bound — the first run behaves like a full export, and\nafter a failed run the next run reuses the last successful timestamp so changed records are\nnot missed.","properties":{"dateField":{"type":"string","description":"Record timestamp field(s) compared against the last successful run time to identify\nchanged records. Accepts a single field or multiple comma-separated fields, processed\nsequentially — useful when different operations update different timestamp fields.\nIf the flow's own downstream steps update the exported records, add export criteria\nthat exclude already-processed records (or use a creation-time field for process-once\nflows) so each run doesn't re-export what the previous run wrote. Not supported on\nHTTP exports: embed {{lastExportDateTime}} in the relativeURI or body instead;\nincluding dateField there makes the configuration invalid. For Salesforce this\nfield is required and defaults to the standard timestamp fields (LastModifiedDate,\nCreatedDate, SystemModstamp, LastActivityDate, LastViewedDate, LastReferencedDate) plus\nany custom timestamp fields."},"dateFormat":{"type":"string","description":"Moment.js format string applied to the cutoff timestamp, including {{lastExportDateTime}}\nwhen used in HTTP requests. Leave unset unless the source system requires a non-ISO8601\nformat; ISO 8601 is used by default. Date-only formats truncate the time portion,\nwidening the filter window."},"lagOffset":{"type":"integer","description":"Buffer in milliseconds subtracted from the last successful run timestamp, creating an\noverlapping window that catches records still propagating when the previous run executed.\nSet it when records created or modified near the run time are occasionally skipped due to\nreplication or indexing delays. Keep it as low as possible — larger values reprocess\nredundant records. A negative value shifts the window forward (look-ahead) instead of back."},"startDate":{"type":["string","null"],"format":"date-time","description":"Explicit lower-bound cutoff for the first run, overriding the default of starting from the\nbeginning of time. Subsequent runs use the platform-managed last-successful-run timestamp.\nSet it to backfill from a specific point rather than exporting all history."}}},"Test":{"type":"object","description":"Configures test exports that cap the number of records retrieved, for safely developing and\nvalidating against small data samples. Required when the export's type is \"test\"; omit for\nother export types. A test export behaves like a standard export in every other way (filters,\npagination, processing) and stores no state between runs.","properties":{"limit":{"type":"integer","default":1,"description":"Caps the total records a test run processes, counted on top-level records before\noneToMany processing; the maximum exists to prevent accidentally processing large\ndatasets during development. The cap applies across pages — processing stops once the\nlimit is reached regardless of pageSize. When transitioning to production, leave this in\nplace and change the export's type field; the limit then no longer applies.","minimum":1,"maximum":100}}},"Once":{"type":"object","description":"Configures flag-based exports that process each record exactly once. Required when the\nexport's type is \"once\"; omit for other export types. Each run retrieves records where the\ntracking boolean field is false, then sets that field to true after successful processing so\nlater runs skip them; if a run fails, the flags are left unchanged and the records are\nretried automatically on the next run.","properties":{"booleanField":{"type":"string","description":"API field name of the boolean/checkbox in the source system that tracks processed\nrecords: the export selects only records where this field is false, then sets it to true\nin batches after each successfully processed page. The field must be writeable by the\nexport's connection. Ensure no other process updates the same field — use a separate\nflag per export process — or records may be skipped unexpectedly."}}},"Webhook":{"type":"object","description":"Configuration for webhook listeners that receive data through incoming HTTP requests. Required when the export's `type` is `webhook`; omit for other export types. The platform generates a unique endpoint URL, validates each incoming request using the configured `verify` method, passes the payload to subsequent flow steps, and returns a configurable HTTP response to the caller.","properties":{"provider":{"type":"string","description":"Source application sending the webhook, used to pre-configure security settings and payload parsing for that platform. Use `custom` (the default when omitted) for unlisted providers or when you need full manual control over the security configuration. Provider-specific choices may require credentials (tokens, keys) mandated by that platform.","enum":["github","shopify","travis","travis-org","slack","dropbox","onfleet","helpscout","errorception","box","stripe","aha","jira","pagerduty","postmark","mailchimp","intercom","activecampaign","segment","recurly","shipwire","surveymonkey","parseur","mailparser-io","hubspot","integrator-extension","custom","sapariba","happyreturns","typeform"]},"verify":{"type":"string","description":"Verification method applied to every incoming request before processing; required for all webhook exports. Each method needs companion fields: `hmac` requires `key`, `algorithm`, `encoding`, and `header` (except on connector-backed webhooks, where the connector definition supplies them); `token` requires `token`, with `tokenLocation` defaulting to `body` and selecting which location-specific field applies; `basic` requires `username` and `password`; `secret_url` requires `token`. Prefer `hmac` when the source system supports it — it is the most secure option; `secret_url` relies only on URL obscurity and suits non-sensitive data or testing.","enum":["token","hmac","basic","secret_url"]},"token":{"type":"string","description":"Shared secret used when `verify` is `token` or `secret_url`. For `token` verification, the value found at `path` in each request must exactly match (case- and whitespace-sensitive) or the request is rejected with a 401. For `secret_url`, the token is embedded in the webhook URL to create a hard-to-guess endpoint — generate a random, high-entropy value and treat it as a sensitive credential."},"algorithm":{"type":"string","description":"Hashing algorithm used to validate HMAC signatures when `verify` is `hmac`. Must match the algorithm the webhook sender uses — a mismatch causes every request to be rejected. Use `sha256` unless the provider explicitly requires another value.","enum":["sha1","sha256","sha384","sha512"]},"encoding":{"type":"string","description":"Encoding of the HMAC signature value when `verify` is `hmac`. Must match the encoding the webhook sender uses — a mismatch causes requests to be rejected even when the signature is otherwise correct.","enum":["hex","base64"]},"key":{"type":"string","description":"Secret used to validate signatures when `verify` is `hmac`. The system computes a signature of the request body using this key and the configured `algorithm`, then compares it with the signature sent in the request header named by `header`. Treat it as a highly sensitive credential — never expose it in repositories or logs."},"header":{"type":"string","description":"Name of the request header that carries the HMAC signature when `verify` is `hmac`. Must match the header name the webhook sender uses (header names are case-insensitive); requests without this header are rejected with a 401. Signature prefixes in the header value (such as `sha256=`) are handled automatically."},"tokenLocation":{"type":"string","enum":["body","header","queryParam"],"default":"body","description":"Where the verification token is found when `verify` is `token`. Each location uses a different companion field: `body` uses `path`, `header` uses `tokenHeaderName` (and `tokenHeaderScheme`), `queryParam` uses `tokenQueryParamName`."},"path":{"type":"string","description":"JSON path into the request body holding the verification token when `verify` is `token` and `tokenLocation` is `body` (e.g. `meta.token`). The value at this path must exactly match `token` or the request is rejected."},"tokenHeaderName":{"type":"string","description":"Request header carrying the verification token when `verify` is `token` and `tokenLocation` is `header`."},"tokenHeaderScheme":{"type":"string","enum":["bearer","custom","none"],"default":"bearer","description":"Scheme prefixing the token in the header when `tokenLocation` is `header`."},"customTokenScheme":{"type":"string","description":"Custom header scheme prefix used when `tokenHeaderScheme` is `custom`."},"tokenQueryParamName":{"type":"string","description":"Query parameter carrying the verification token when `verify` is `token` and `tokenLocation` is `queryParam`."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector backing this listener when the webhook is provided by an assistant/connector (e.g. Slack); set by the platform for connector-backed listeners."},"requestMediaType":{"type":"string","enum":["json","xml","csv","urlencoded","plaintext"],"description":"Overrides how the incoming request body is parsed when the provider sends a non-standard content type. When omitted, the body is parsed by its Content-Type header."},"pathToRecords":{"type":"string","description":"JSON path into the incoming payload to the array of records to emit; when omitted, the whole payload is emitted as a single record."},"includeParentData":{"type":"boolean","description":"When true and `pathToRecords` is set, each emitted record also carries the surrounding parent fields from the payload."},"username":{"type":"string","description":"Username half of the credentials when `verify` is `basic`. Incoming requests must include an `Authorization: Basic` header carrying the base64-encoded `username:password` pair. Use only over HTTPS to prevent credential interception."},"password":{"type":"string","description":"Password half of the credentials when `verify` is `basic`, validated together with `username` from the request's `Authorization` header. Use a strong, unique value and treat it as a sensitive credential."},"successStatusCode":{"type":"integer","description":"HTTP status code returned to the caller after successful processing; must be a valid 2xx code. The default 204 returns no response body and causes `successBody` to be ignored — set 200 or 202 when the caller needs a response body or expects a specific code.","default":204},"successBody":{"type":"string","description":"Response body returned to the caller after successful processing; ignored when `successStatusCode` is 204. Content type is set by `successMediaType`, and the value can be static text or structured JSON/XML, including handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Sets the Content-Type header on successful webhook responses. Only takes effect when a `successBody` is returned (a status code other than 204), and must match the actual format of that body.","default":"json","enum":["json","xml","plaintext"]},"successResponseHeaders":{"type":"array","description":"Custom headers added to successful webhook responses — for example CORS headers or correlation IDs. Headers defined here take precedence over automatically set headers such as Content-Type, and values support handlebars expressions for dynamic content.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on successful webhook responses; headers defined here take precedence over automatically set headers such as Content-Type."},"value":{"type":"string","description":"Value sent for the header; supports handlebars expressions for dynamic content."}}}},"challengeResponseHeaders":{"type":"array","description":"Custom headers returned for webhook subscription verification (challenge) requests, which providers send before delivering real events. Required header values vary by provider — consult the provider's documentation, since incorrect challenge headers can prevent the subscription from being verified.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the header to set on challenge (subscription verification) responses."},"value":{"type":"string","description":"Value sent for the header; consult the provider's documentation for required challenge header values."}}}},"challengeSuccessBody":{"type":"string","description":"Response body returned for webhook subscription verification (challenge) requests. Many providers require echoing back a challenge value from the request, which handlebars expressions can access — for example `{{hub.challenge}}` (Facebook/Instagram) or `{\"challenge\":\"{{challenge}}\"}` (Slack). An incorrect challenge response prevents the subscription from being verified."},"challengeSuccessStatusCode":{"type":"integer","description":"HTTP status code returned for webhook subscription verification (challenge) requests. Most providers expect the default 200; change it only when the provider's verification explicitly requires a different code.","default":200},"challengeSuccessMediaType":{"type":"string","description":"Sets the Content-Type header on challenge responses. Must match both the format of `challengeSuccessBody` and the provider's requirements — for example, Slack expects `json` while Facebook/Instagram verification expects `plaintext`.","default":"json","enum":["json","xml","plaintext"]}},"if":{"properties":{"verify":{"const":"hmac"}},"required":["verify"],"not":{"required":["_httpConnectorId"]}},"then":{"required":["key","algorithm","encoding","header"]},"else":{"if":{"properties":{"verify":{"const":"token"}},"required":["verify"]},"then":{"required":["token"],"if":{"properties":{"tokenLocation":{"const":"body"}},"required":["tokenLocation"]},"then":{"required":["path"]},"else":{"if":{"properties":{"tokenLocation":{"const":"header"}},"required":["tokenLocation"]},"then":{"required":["tokenHeaderName"]},"else":{"if":{"properties":{"tokenLocation":{"const":"queryParam"}},"required":["tokenLocation"]},"then":{"required":["tokenQueryParamName"]},"else":{"required":["path"]}}}},"else":{"if":{"properties":{"verify":{"const":"basic"}},"required":["verify"]},"then":{"required":["username","password"]},"else":{"if":{"properties":{"verify":{"const":"secret_url"}},"required":["verify"]},"then":{"required":["token"]}}}}},"Simple":{"type":"object","description":"Configuration for `simple` (data-loader) exports — exports that accept manually uploaded\nfiles through the data-loader UI instead of fetching data from a connection. Relevant only\nwhen the export's `type` is `simple`; the uploaded content is parsed using the same file\nsettings as file-based exports.","properties":{"file":{"$ref":"#/components/schemas/File"}}},"File":{"type":"object","description":"Controls how files are parsed, filtered, and processed across all file-based exports\n(FTP/SFTP, Amazon S3, simple file uploads, and other file sources). The type field selects\nthe file format and determines which format-specific object (csv, json, xlsx, xml, or\nfileDefinition) must be configured; the output field selects whether files are parsed into\nrecords, transferred as blobs, or listed as metadata only. The filter object selectively\nskips files before processing.","properties":{"encoding":{"type":"string","description":"Character encoding used to read and parse file content. If the encoding is unknown, try\nutf8 first (the default), then win1252 for Western-language files with garbled\ncharacters; consider the geographic origin of the data when selecting.","enum":["utf8","win1252","utf-16le","gb18030","macroman","iso88591","shiftjis"]},"type":{"type":"string","description":"Format of the files being processed; determines which format-specific configuration\nobject (csv, json, xlsx, xml, or fileDefinition) must be populated — other format\nobjects are ignored. Required for all file-based exports except blob exports (export\ntype \"blob\" or output \"blobKeys\").","enum":["csv","json","xlsx","xml","filedefinition"]},"output":{"type":"string","description":"Processing mode for retrieved files: parse contents into records, transfer files as\nunparsed blobs, or return only file metadata. Determines what data is passed to\nsubsequent flow steps.","enum":["records","metadata","blobKeys"]},"skipDelete":{"type":"boolean","description":"When true, source files remain on the file server after processing; when false (the\ndefault), files are deleted after successful processing. Files that fail processing are\nnever deleted, regardless of this setting. Enable retention when files must be processed\nby other flows or kept for compliance."},"compressionFormat":{"type":"string","description":"Compression format of incoming files, which are decompressed before any other processing\n(parsing, filtering). Set this only when the source always delivers compressed files —\nif a file marked as compressed is not actually compressed, processing fails. Leave unset\nwhen files arrive uncompressed or only sometimes compressed.","enum":["gzip","zip"]},"purgeInternalBackup":{"type":"boolean","description":"When true, Celigo keeps no internal backup copies of files processed by this export;\nwhen false (the default), copies are retained for your account's retention period and\nare available for reprocessing or troubleshooting. Applies only to this export and only\nto Celigo's internal copies — source files are governed by skipDelete. Enable for highly\nsensitive data or zero-retention policies; without backups, recovery may require\nre-obtaining files from the source system."},"decrypt":{"type":"string","description":"Decryption applied to incoming files before any other processing; decryption runs before\ndecompression, and a decryption failure fails the file's processing entirely. The\nconnection must already be configured with the private key (and passphrase, if\napplicable) matching the public key used to encrypt the files. Only PGP/GPG encryption\nis currently supported.","enum":["pgp"]},"batchSize":{"type":["integer","null"],"description":"Number of files retrieved per batch; if a batch fails, the whole batch is retried\n(stored as `null` when not configured). Use\nlower values (10-50) for large files to reduce timeout and memory pressure, and higher\nvalues for many small files to improve throughput. Controls file retrieval only — record\npaging is governed by the export's pageSize.","maximum":1000},"sortByFields":{"type":"array","description":"Sorts the records parsed from each file before they are processed, establishing a\ndeterministic processing order (for example, chronological or priority-based). Sorting\nhappens after parsing but before any filtering or grouping, and does not modify the\nsource files. Sorting by the same fields used in groupByFields improves grouping\nperformance.","items":{"type":"object","properties":{"field":{"type":"string","description":"Record field to sort by; use dot notation for nested properties (e.g.\ncustomer.name). Field names are case-sensitive."},"descending":{"type":"boolean","description":"When true, sorts this field in descending order (newest/highest first); when false\nor omitted, sorts ascending. Directions can be mixed across fields in a\nmulti-field sort."}}}},"groupByFields":{"$ref":"#/components/schemas/GroupBy"},"groupEmptyValues":{"type":"boolean","description":"When true, records whose groupByFields values are empty are still grouped together rather\nthan each forming its own group; when false (the default), empty-keyed records are not\ngrouped. Only relevant when groupByFields is set."},"csv":{"type":"object","description":"Parsing settings for delimiter-separated text files (CSV, TSV, pipe-delimited, and\nsimilar). Configure when type is \"csv\".\n\nRequired when type is csv.","properties":{"columnDelimiter":{"type":"string","description":"Character sequence separating fields within each row; comma when omitted. Use \"\\t\"\nfor tab-delimited files; European-locale exports often use semicolons. An incorrect\ndelimiter is the most common cause of parsing failures."},"rowDelimiter":{"type":"string","description":"Character sequence marking the end of each record; auto-detected from file content\nwhen omitted. Set explicitly (\"\\n\", \"\\r\\n\", or \"\\r\") only when auto-detection fails,\nsuch as for files with mixed line endings — an incorrect value merges or splits\nrecords."},"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data, and\nthose names are available in mappings. When false, every row is treated as a data\nrecord and fields are referenced by position."},"trimSpaces":{"type":"boolean","description":"When true, removes leading and trailing whitespace from every field value during\nparsing; when false (the default), whitespace is preserved exactly as in the source.\nHeader row values are always trimmed regardless of this setting, and spaces between\nwords are never affected."},"rowsToSkip":{"type":"integer","description":"Number of rows at the top of the file to ignore before parsing begins — useful for\nreport titles, timestamps, or other metadata above the data. The header row (when\nhasHeaderRow is true) is expected after the skipped rows."},"disableQuoteAndStripEnclosingQuotes":{"type":"boolean","description":"When true, disables CSV quote processing: quotes are treated as literal characters,\nenclosing quotes are stripped, and delimiters inside quoted text split the field.\nWhen false (the default), standard RFC 4180 quoting applies and quoted fields\nprotect embedded delimiters. Enable only for files with non-standard or malformed\nquoting; review this setting first when field counts vary unexpectedly between rows."},"keyColumns":{"type":"array","description":"Field names whose values together identify a record's group when consecutive rows\nshare the same key — used to merge multi-line records (e.g. an order header repeated\nacross line-item rows) into a single record. Leave empty for one record per row; the\ncolumns must exist in the parsed header.","items":{"type":"string"}}}},"json":{"type":"object","description":"Parsing settings for JSON files. Configure when type is \"json\". resourcePath locates the\narray of records when they are nested inside a container object; malformed JSON fails\nthe entire file's processing.\n\nRequired when type is json.","properties":{"resourcePath":{"type":"string","description":"Dot-notation path to the array of records within the JSON structure (e.g.\n\"response.data.customers\"); leave empty when the file's root is already the record\narray. The path must resolve to an array of objects — array indexing and wildcards\nare not supported. A path that resolves to nothing produces zero records without\nraising an error."}}},"xlsx":{"type":"object","description":"Parsing settings for Microsoft Excel (.xlsx) workbooks. Configure when type is \"xlsx\".\nCalculated cell values are extracted rather than formulas; legacy .xls files are not\nsupported — use the modern Open XML format.\n\nRequired when type is xlsx.","properties":{"hasHeaderRow":{"type":"boolean","description":"When true (the default), the first row is read as field names rather than data;\nblank header cells are auto-named and duplicate names are made unique with suffixes.\nWhen false, every row is treated as data and fields receive generic positional names\n(Column1, Column2, ...)."}}},"xml":{"type":"object","description":"Parsing settings for XML documents. Configure when type is \"xml\". resourcePath is an\nXPath expression selecting the elements treated as records; namespaces are handled\nautomatically.\n\nRequired when type is xml.","properties":{"resourcePath":{"type":"string","description":"XPath expression selecting the elements treated as records — each matching element\nbecomes one record, with its child elements as fields. Required for XML parsing;\nthere is no default. Use an absolute path (/Root/Order) when the structure is fixed,\n//Element to match at any depth, or predicates (//Element[@type=\"product\"]) to\nfilter; XPath is case-sensitive, and a non-matching path yields zero records."}}},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"fileDefinition":{"type":"object","description":"Parsing via a predefined file definition resource, for formats the standard parsers\ncannot handle — fixed-width files, EDI documents (X12, EDIFACT), and multi-record-type\nor proprietary formats. Configure when type is \"filedefinition\".\n\nRequired when type is filedefinition.","properties":{"_fileDefinitionId":{"type":"string","format":"objectId","description":"File definition resource containing the parsing rules for this format. Must\nreference an existing, accessible file definition — never guess or fabricate the ID.\nDefinitions are reusable across exports, so changing one affects every export that\nuses it."},"allowPartialSuccess":{"type":"boolean","description":"When true, a file whose records partially fail parsing against the file definition\nstill emits the records that did parse, instead of failing the entire file. Applies to\nfile-definition (fixed-width, EDI) parsing only."}}},"filter":{"description":"Selects which files are processed: files matching the filter criteria are exported,\nand non-matching files are skipped entirely before processing begins. Filterable\nfields come from each file's metadata — most providers expose filename, filesize,\nand lastmodified (e.g. [\"endswith\", [\"extract\", \"filename\"], \".csv\"]).","allOf":[{"$ref":"#/components/schemas/Filter"}]},"backupPath":{"type":"string","description":"Path where backup copies of source files are stored before processing."},"directory":{"type":"object","required":["pathMode"],"description":"Structured source location for cloud file-provider sources (Google Drive shared drives,\nBox, Dropbox), replacing the flat path used by classic FTP/S3 sources. Select the location\nby folder ID or by a path relative to a configured storage root via pathMode. For these\ncloud providers, directoryId mode addresses the folder by id alone — the flat\nrelative-path field is not consulted at runtime.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the directory is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the source directory (e.g. a Google Drive folder ID); set\nwhen pathMode is directoryId. This is the file provider's own ID, not a Celigo resource ID."},"name":{"type":"string","description":"Display name of the folder identified by id, kept for readability in the UI; the\nfolder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root (e.g. a Google Drive shared-drive ID) the relative\npath resolves against; set when pathMode is relativePath. The provider's own ID, not a Celigo ID."},"storageRootName":{"type":"string","description":"Display name of the storage root identified by storageRootId, retained for reference in the UI."}}},"backupDirectory":{"type":"object","required":["pathMode"],"description":"Structured destination for backup copies of source files on cloud file providers — the\nfile-provider counterpart to backupPath. Addressed the same way as directory.","properties":{"pathMode":{"type":"string","enum":["relativePath","directoryId"],"description":"How the backup location is addressed — by provider folder ID, or by a path relative to a configured storage root."},"id":{"type":"string","description":"Provider-native folder ID of the backup directory; set when pathMode is directoryId."},"name":{"type":"string","description":"Display name of the backup folder identified by id, kept for readability in the UI;\nthe folder browser fills it when the location is picked visually."},"storageRootId":{"type":"string","description":"Provider-native ID of the storage root the backup relative path resolves against; set when pathMode is relativePath."}}}}},"IncludeParentData":{"type":"boolean","description":"When true and a path to records is configured on the export (`pathToRecords` for MongoDB and DynamoDB, `http.response.resourcePath` for HTTP, `file.json`/`file.xml` `resourcePath` for file-based exports), the data outside that path is attached to each extracted record as a `_PARENT` object, keeping the surrounding envelope available to downstream steps. When omitted or false, records are emitted without `_PARENT`, exactly as before. Constraints: on HTTP exports this option cannot be combined with `useXpathParser: true` (rejected at save with `EXPORT_INCLUDE_PARENT_DATA_XPATH_UNSUPPORTED`), and XML responses must resolve to the default converted-JSON parse mode — a run whose XML parser resolves to DOM/XPath mode (for example, because a connection-level field uses an advanced XPath expression) fails at start with the same error rather than silently omitting `_PARENT`. On file-based exports, it requires `file.type` of `json` with `file.json.resourcePath` configured — XML file envelope capture is not yet supported (the streaming XML parser emits no envelope event; XML support arrives with a parsers-package enhancement) — and any other file configuration is rejected at save with `EXPORT_INCLUDE_PARENT_DATA_UNSUPPORTED_FILE_TYPE`."},"Filter":{"type":"object","description":"Configuration for selectively processing records based on specified criteria. This object enables\nprecise control over which items are included or excluded from processing operations.\n\n**Filter behavior**\n\nWhen configured, the filter is applied before processing begins:\n- Items that match the filter criteria are processed\n- Items that don't match are completely skipped\n- No partial processing is performed\n\n**Implementation approaches**\n\nThere are two distinct filtering mechanisms available:\n\n**Rule-Based Filtering (`type: \"expression\"`)**\n- **Best For**: Common filtering patterns based on standard attributes\n- **Capabilities**: Filter by names, values, dates, numerical ranges, text patterns\n- **Advantages**: Declarative, no coding required, consistent performance\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear, static criteria for selection\n\n**Script-Based Filtering (`type: \"script\"`)**\n- **Best For**: Complex logic, dynamic criteria, or business rules\n- **Capabilities**: Full programmatic control, access to complete metadata\n- **Advantages**: Maximum flexibility, can implement any filtering logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Simple rules aren't sufficient or logic needs to be dynamic\n","properties":{"type":{"type":"string","description":"Determines which filtering mechanism to use. This choice affects which properties\nmust be configured and how filtering logic is implemented.\n\n**Available types**\n\n**Rule-Based Filtering (`\"expression\"`)**\n- **Required Config**: The `expression` object with rule definitions\n- **Behavior**: Evaluates declarative rules against item attributes\n- **Best For**: Common patterns like name matching, date ranges, value limits\n- **Advantages**: Simpler to configure, no custom code required\n\n**Script-Based Filtering (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to determine which items to process\n- **Best For**: Complex conditions, business logic, dynamic criteria\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard filtering needs (name, size, date), use `\"expression\"`\n2. For complex logic or conditions not covered by expressions, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based filtering. This object enables filtering\nitems based on common attributes without requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define filtering rules that\ncan match against item attributes like name, type, value, date, and other properties.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Rules can be combined with AND/OR logic\n- Each rule can check a specific attribute\n- Multiple conditions can be applied (ranges, pattern matching, exact matches)\n\n**Common filter patterns**\n\n1. **Pattern matching**: Using wildcards like `*` and `?`\n2. **Value range filtering**: Numbers between min and max values\n3. **Date range filtering**: Items created/modified within specific time ranges\n4. **Status checking**: Items with specific status values or properties\n\nFor AI agents: Rule-based filtering should be your first choice when the filtering criteria\ncan be expressed in terms of standard attributes. Only use script-based filtering when\nmore complex logic is required.\n","properties":{"version":{"type":"string","description":"Version identifier for the expression format. Currently only version \"1\" is supported.\n\nThis field ensures future compatibility if the expression format evolves. Always set to \"1\"\nfor current implementations.\n","enum":["1"]},"rules":{"type":"array","description":"Expression array defining filter conditions using prefix notation. The first element is the operator,\nfollowed by its operands which may themselves be nested expression arrays.\n\nThe rule expression follows this pattern:\n- First element: Operator name (string)\n- Remaining elements: Operands for that operator (values or nested expressions)\n\n**Expression structure**\n\nFilter expressions use a prefix notation where operators appear before their operands:\n```\n[operator, operand1, operand2, ...]\n```\n\n**Comparison Operators**\n- `\"equals\"`: Exact match (equals)\n- `\"notequals\"`: Not equal to value (not equals)\n- `\"greaterthan\"`: Value is greater than specified value (is greater than)\n- `\"greaterthanequals\"`: Value is greater than or equal to specified value (is greater than or equals)\n- `\"lessthan\"`: Value is less than specified value (is less than)\n- `\"lessthanequals\"`: Value is less than or equal to specified value (is less than or equals)\n- `\"startswith\"`: String starts with specified prefix (starts with)\n- `\"endswith\"`: String ends with specified suffix (ends with)\n- `\"contains\"`: String contains specified substring (contains)\n- `\"doesnotcontain\"`: String does not contain specified substring (does not contain)\n- `\"isempty\"`: Field is empty or null (is empty)\n- `\"isnotempty\"`: Field contains a value (is not empty)\n- `\"matches\"`: Matches specified pattern (matches)\n\n**Logical Operators**\n- `\"and\"`: All conditions must be true\n- `\"or\"`: At least one condition must be true\n- `\"not\"`: Negates the condition\n\n**Field Access and Type Conversion**\n- `\"extract\"`: Access a field from the item by name\n- `\"settings\"`: Access a custom setting from the flow, flow step, or integration configuration\n- `\"boolean\"`: Convert value to Boolean type\n- `\"epochtime\"`: Convert value to Epoch Time (Unix timestamp)\n- `\"number\"`: Convert value to Number type\n- `\"string\"`: Convert value to String type\n\n**Field Access Details**\n\n**Using `extract` to access record fields:**\n- Retrieves values from the current record being processed\n- Can access nested properties using dot notation (e.g., `\"customer.email\"`)\n- Returns the raw field value which may need type conversion\n\n**Using `settings` to access configuration values:**\n- Retrieves values from the integration's configuration settings\n- Supports different scopes with prefix notation:\n  - `flow.settingName`: Access flow-level settings\n  - `export.settingName`: Access export-level settings\n  - `import.settingName`: Access import-level settings\n  - `integration.settingName`: Access integration-level settings\n- Useful for dynamic filtering based on configuration\n\n**Field Transformations**\n- `\"lowercase\"`: Convert string to lowercase\n- `\"uppercase\"`: Convert string to uppercase\n- `\"ceiling\"`: Round number up to the nearest integer\n- `\"floor\"`: Round number down to the nearest integer\n- `\"abs\"`: Get absolute value of a number\n\nType conversion operators are often necessary when comparing extracted field values against literals or when the field type doesn't match the comparison operator's expected type. For example:\n\n```json\n[\n  \"equals\",\n  [\n    \"number\",  // Convert to number before comparison\n    [\n      \"extract\",\n      \"quantity\"\n    ]\n  ],\n  100\n]\n```\n\nExample with datetime conversion:\n```json\n[\n  \"greaterthan\",\n  [\n    \"epochtime\",  // Convert to Unix timestamp before comparison\n    [\n      \"extract\",\n      \"createdDate\"\n    ]\n  ],\n  1609459200000  // January 1, 2021 as Unix timestamp in milliseconds\n]\n```\n\nExample with transformations:\n```json\n[\n  \"and\",\n  [\n    \"matches\",\n    [\n      \"lowercase\",  // Convert to lowercase before matching\n      [\n        \"string\",\n        [\n          \"extract\",\n          \"categories\"\n        ]\n      ]\n    ],\n    \"netsuite\"\n  ],\n  [\n    \"notequals\",\n    [\n      \"string\",\n      [\n        \"extract\",\n        \"recurrence.pattern.type\"\n      ]\n    ],\n    \"\"\n  ]\n]\n```\n\nExample comparing a record field with a flow setting:\n```json\n[\n  \"equals\",\n  [\n    \"string\",\n    [\n      \"extract\",\n      \"trantype\"\n    ]\n  ],\n  [\n    \"string\",\n    [\n      \"settings\",\n      \"flow.trantype\"\n    ]\n  ]\n]\n```\n\n**Examples**\n\nExample 1: Status field is not equal to \"cancelled\"\n```json\n[\n  \"notequals\",\n  [\n    \"extract\",\n    \"status\"\n  ],\n  \"cancelled\"\n]\n```\n\nExample 2: Filename starts with \"HC\"\n```json\n[\n  \"startswith\",\n  [\n    \"extract\",\n    \"filename\"\n  ],\n  \"HC\"\n]\n```\n\nExample 3: Amount is greater than 100\n```json\n[\n  \"greaterthan\",\n  [\n    \"number\",\n    [\n      \"extract\",\n      \"amount\"\n    ]\n  ],\n  100\n]\n```\n\nExample 4: Order date is after January 1, 2023\n```json\n[\n  \"greaterthan\",\n  [\n    \"extract\",\n    \"orderDate\"\n  ],\n  \"2023-01-01T00:00:00Z\"\n]\n```\n\nExample 5: Category contains any of [\"Urgent\", \"High Priority\"]\n```json\n[\n  \"anyof\",\n  [\n    \"extract\",\n    \"category\"\n  ],\n  [\"Urgent\", \"High Priority\"]\n]\n```\n","items":{"oneOf":[{"title":"String","type":"string"},{"title":"Number","type":"number"},{"title":"Boolean","type":"boolean"},{"title":"Object","type":"object"},{"title":"Array","type":"array"},{"title":"Null","type":"null"}]}}}},"script":{"type":"object","description":"Configuration for programmable script-based filtering. This object enables complex, custom\nfiltering logic beyond what expression-based filtering can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `filter.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to determine which items\nshould be processed.\n\n**Implementation approach**\n\nScript-based filtering works by:\n1. Executing the specified function from the referenced script\n2. Passing item data to the function\n3. Using the function's return value (true/false) to determine inclusion\n\n**Common use cases**\n\nScript filtering is ideal for:\n- Complex business logic that can't be expressed as simple rules\n- Dynamic filtering criteria that change based on external factors\n- Content-based filtering that requires deep inspection\n- Advanced pattern matching beyond simple wildcards\n- Multi-stage filtering with intermediate logic\n\nFor AI agents: Only use script-based filtering when expression-based filtering is insufficient.\nScript filtering requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to the Script resource that contains the filtering logic. This must be a valid\nObjectId of a Script resource that exists in the system.\n\nThe referenced script must contain the function specified in the `function` field\nand must be written to handle filtering specifically. The script receives\nitem data as its input and must return a boolean value indicating whether\nto process the item (true) or skip it (false).\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n"},"function":{"type":"string","description":"Name of the function within the script to execute for filtering decisions. This function\nmust exist in the script referenced by _scriptId.\n\n**Function requirements**\n\nThe specified function must:\n- Accept item data as its first parameter\n- Return a boolean value (true to process the item, false to skip it)\n- Handle errors gracefully\n- Execute efficiently (as it may run for many items)\n\n**Function signature**\n\n```javascript\nfunction filterItems(itemData) {\n  // itemData contains properties of the item being evaluated\n  // Custom logic here\n  return true; // or false to skip the item\n}\n```\n\nFor AI agents: Ensure the function name exactly matches a function defined in the\nreferenced script, as mismatches will cause the filter to fail.\n"}}}}},"Distributed":{"type":"object","description":"Authentication settings for distributed (real-time listener) exports.","properties":{"bearerToken":{"type":"string","description":"Bearer token used to authenticate inbound distributed export requests. Optional — most\ndistributed listeners (NetSuite, Salesforce real-time) use no token. Write-only and stored\nencrypted; treat it as a sensitive credential.","format":"password"}}},"Cdc":{"type":"object","description":"Change-data-capture configuration for real-time listener exports (the \"Listen for real-time\ndata\" source step). Present only when `type` is `stream`. Set on `MongodbExport` (MongoDB change\nstreams) and `RDBMSExport` (SQL Server CDC and PostgreSQL logical replication); the listener\nstreams change events continuously instead of fetching records on a schedule.\n\nOn save the API normalizes the `properties` grid into the typed fields: a `snapshot.mode`\nentry populates `snapshotMode` and a `capture.mode` entry populates `captureMode`. Every\nstream export must resolve a snapshot mode from one of those two places.","properties":{"captureMode":{"type":"string","enum":["change_streams_update_full","change_streams_update_full_with_pre_image"],"default":"change_streams_update_full","description":"How MongoDB change-stream events are materialized into records. Use\n`change_streams_update_full_with_pre_image` when downstream steps need the document's prior\nstate. MongoDB listeners only — `RDBMSExport` (SQL Server CDC, PostgreSQL) does not set this."},"snapshotMode":{"type":"string","enum":["initial","no_data","when_needed","initial_only"],"default":"no_data","description":"Whether the listener seeds existing rows before streaming changes. Use `initial` to backfill\nexisting data on the first run; `no_data` to stream only new changes."},"slotName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL logical replication slot the listener consumes. PostgreSQL listeners\nonly. When omitted, the platform manages the slot name. Must be a valid PostgreSQL\nidentifier (lowercase letters, numbers, or underscores, starting with a letter or\nunderscore)."},"publicationName":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"Name of the PostgreSQL publication that defines which tables stream changes. PostgreSQL\nlisteners only. When set, the publication is the sole table filter and `rdbms.tables`\nstays unset. Must be a valid PostgreSQL identifier."},"cursor":{"type":"string","description":"Server-managed stream position marker (where the listener resumes reading change events).\nMaintained by the platform as events are consumed; the UI exposes a reset workflow for it\nunder Cursor Management."},"paths":{"type":"array","items":{"type":"string"},"description":"Dot-notation paths within each raw change event to retain in the emitted record. MongoDB\nlisteners default to `[\"payload\"]` (the whole change document); SQL Server and PostgreSQL\nlisteners commonly select `payload.after`, `payload.op`, and related fields to expose the\nchanged row and operation type."},"intervalTime":{"type":"integer","default":300,"description":"Polling interval, in seconds, at which the listener checks the source for new change events."},"properties":{"type":"array","description":"Connector-engine settings passed through to the underlying CDC connector as name/value\npairs. Mirrors the form's additional-properties grid: the required keys (`capture.mode`\nand `snapshot.mode` for MongoDB, `snapshot.mode` for SQL Server and PostgreSQL) are\nserialized first, followed by optional keys such as `field.exclude.list`,\n`column.include.list`, or `snapshot.collection.filter.overrides.<db>.<collection>`.\nOn save the API also lifts `snapshot.mode` / `capture.mode` entries into the typed\n`snapshotMode` / `captureMode` fields.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","description":"Connector property key (e.g. `capture.mode`, `snapshot.mode`, `field.exclude.list`)."},"value":{"type":"string","description":"Connector property value."}}}}}},"FileSystem":{"type":"object","description":"Defines which files to read from a local or mounted folder on the host running the\non-premise agent. Required when the _connectionId field references a file-system (on-premise)\nconnection; must not be included for other connection types.","required":["directoryPath"],"properties":{"directoryPath":{"type":"string","description":"Folder on the on-premise agent's host to read files from; the agent's OS account must\nhave read permission on it. Accepts a local OS path or a UNC network share, and supports\nhandlebars templates for dynamic folders."}}},"Http":{"type":"object","description":"Configuration for HTTP exports. Required when the export's `_connectionId` references a\nconnection of type `http`, and on `NetSuiteHTTPExport` (NetSuite's REST APIs on a `netsuite`\nconnection, where `nsDomainType` supplies the host).","properties":{"type":{"type":"string","enum":["file","blob","csvstream"],"description":"Set to `file` when the export works with files rather than a record-returning endpoint: raw file downloads (PDFs, images, binary data) and the folder mode of the cloud file providers (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, Celigo Storage), where each file in the folder is parsed by the `file` object's `type` (csv, json, xml, xlsx, filedefinition — including EDI) into records; the `file` object must also be configured. Leave undefined for standard data exports that return structured records (JSON, XML, GraphQL, SOAP responses) — the response is then parsed into records for downstream steps. When set to `file` or `blob`, the export appears as a \"Transfer\" step in Flow Builder instead of a standard \"Export\" step."},"formType":{"type":"string","enum":["http","rest","graph_ql","assistant","assistant_graphql"],"description":"Authoring mode of the HTTP request form. Controls which editor the UI presents\n(standard HTTP, legacy REST, GraphQL, or connector-assistant driven) and how the\nrequest fields are interpreted. When omitted, the standard HTTP form is used."},"method":{"type":"string","description":"HTTP method used to request data from the target API. Consult the target API's documentation to determine the appropriate method.","enum":["GET","POST","PUT","PATCH","DELETE"]},"followRedirects":{"type":"boolean","default":true,"description":"When explicitly false, 3xx responses are not followed — the redirect\nresponse itself (status code, `Location` header, body) becomes the\nrecord. Omitted or true follows allowed redirects (the default\nbehavior)."},"maxRedirects":{"type":"integer","minimum":1,"maximum":10,"description":"Caps how many consecutive 3xx redirects are followed. Only applies\nwhen `followRedirects` is not false; to not follow at all, set\n`followRedirects: false` rather than `maxRedirects: 0`. Decimal\nvalues are rejected on save."},"relativeURI":{"type":"string","description":"Resource path appended to the connection's `baseURI` to form the complete request URL. Path segments, query parameters, or the entire value can be built with handlebars expressions for endpoints determined at runtime. For lookup exports (`isLookup: true`) with mappings configured, handlebars always render against the original pre-mapped input record, so fields removed or renamed by mappings remain available for URI construction. On `NetSuiteHTTPExport` the base URL is derived from the NetSuite connection and `nsDomainType`, so the path starts at `/services/rest/...` or `/app/site/hosting/restlet.nl`."},"headers":{"type":"array","description":"Headers specific to this export, merged with (and able to override) headers defined on the connection. Define common headers such as authentication on the connection instead. Values support handlebars expressions; for lookup exports with mappings, values render against the pre-mapped input record.","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the HTTP header to send; a header defined here overrides a same-named header from the connection."},"value":{"type":"string","description":"Value sent for the header. Supports handlebars expressions; for lookup exports with mappings, the value renders against the pre-mapped input record."}}}},"requestMediaType":{"type":"string","description":"Overrides the connection-level request media type for this export. Set only when this endpoint requires a different format than the connection default.","enum":["json","xml","urlencoded","form-data","plaintext"]},"body":{"type":"string","description":"Request body sent with POST, PUT, or PATCH requests, typically carrying query or filter criteria for APIs (such as GraphQL or SOAP) that expect them in the body. The content must match the format set by `requestMediaType` and supports handlebars expressions for dynamic values."},"successMediaType":{"type":"string","description":"Media type used to parse successful response bodies. Set only when the response format differs from the request format.","enum":["json","xml","csv","plaintext"]},"errorMediaType":{"type":"string","description":"Media type used to parse error response bodies. Set only when error responses use a different format than the request.","enum":["json","xml","plaintext"]},"_asyncHelperId":{"type":"string","format":"objectId","description":"AsyncHelper resource that handles polling for long-running operations on APIs that process requests asynchronously (HTTP 202 responses, job tickets, feed or document IDs). Set when the export must submit a request, poll for status, and retrieve results once the external process completes — for example Amazon SP-API feeds or large report generators."},"once":{"type":"object","description":"Callback configuration for once exports, used to mark records as exported in the source system after successful processing.","properties":{"relativeURI":{"type":"string","description":"Relative path (starting with `/`) called on the source system to mark each record as exported after successful processing. Supports handlebars variables and renders against the pre-mapped record — mappings do not apply to the callback URI."},"method":{"type":"string","description":"HTTP method used for the mark-as-exported callback request.","enum":["GET","PUT","POST","PATCH","DELETE"]},"body":{"type":"string","description":"Request body sent with the mark-as-exported callback. Supports handlebars expressions for dynamic values."}}},"paging":{"type":"object","description":"Controls how the export requests subsequent pages when the API returns multi-page responses. The `method` field determines which companion fields are required and how each next page is requested. For the page, skip, and token methods, reference the matching pagination variable (`{{export.http.paging.page}}`, `{{export.http.paging.skip}}`, or `{{export.http.paging.token}}`) in the relative URI or request body — misconfigured pagination is a common cause of incomplete data retrieval.","properties":{"method":{"type":"string","description":"Pagination strategy used to request each subsequent page; match it to the mechanism documented by the target API. Determines which companion fields are required: `token` needs `path` and `pathLocation`, `url` needs `path`, `relativeuri` needs `relativeURI`, `body` needs `body`, while `linkheader` typically needs no extra configuration. Using the wrong method results in errors or incomplete data retrieval.","enum":["linkheader","page","skip","token","url","relativeuri","body"]},"page":{"type":"integer","description":"Starting page number for `method: page`. Set to 1 for APIs whose first page is not zero-indexed; when omitted, paging starts at 0. The value is incremented automatically for each subsequent page request."},"skip":{"type":"integer","description":"Starting offset for `method: skip`. Rarely needed — most APIs start at 0, and the value is incremented by the page size automatically for each subsequent request. Set only when the API requires a non-zero starting offset."},"token":{"type":"string","description":"Initial token for `method: token`. Leave empty for normal pagination — the first request is sent without a token, and subsequent tokens are extracted from each response via `path`. Set only to resume from a known token or for APIs that require a token on the first request."},"path":{"type":"string","description":"Location of the pagination value in each response — the continuation token for `method: token`, or the complete next-page URL for `method: url`. When `pathLocation` is `body`, use a dot-notation JSON path (e.g. `meta.nextToken`); when `header`, use the exact case-sensitive header name. Not used by other pagination methods."},"pathLocation":{"type":"string","description":"Where the export looks for the pagination token referenced by `path`. Required for `method: token`; not used by other pagination methods.","enum":["body","header"]},"pathAfterFirstRequest":{"type":"string","description":"Alternative token location used for responses after the first page, in the same format as `path`. Set only when the API moves the token to a different location in subsequent responses — setting it unnecessarily can cause pagination to fail."},"relativeURI":{"type":"string","description":"Overrides the main relative URI for second and later page requests; leave empty when the main relative URI works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response` (the prior response body), `previous_page.last_record` (the last record of the prior page), and `previous_page.headers` (the prior response headers)."},"body":{"type":"string","description":"Overrides the main request body for second and later page requests, typically for GraphQL or SOAP APIs that paginate through the body; leave empty when the main body works for all pages. Build it with handlebars using the `previous_page` context — `previous_page.full_response`, `previous_page.last_record`, and `previous_page.headers`."},"mergeBodyParamsToPagingBody":{"type":"boolean","description":"Only applies when `paging.method` is `body`. When true, the body\nparameters produced by the export's mappings at runtime are merged\ninto the evaluated `paging.body` for page 2+ requests, so paging\nrequests keep the same mapped parameters as the first page.\nOmitted/false keeps the original behavior — page 2+ requests send\nonly the evaluated `paging.body`."},"linkHeaderRelation":{"type":"string","description":"Link header relation followed for `method: linkheader` when the API uses a value other than the default `next`. Case-sensitive and must exactly match the `rel` value in the Link header, without the `rel=` prefix."},"resourcePath":{"type":"string","description":"Overrides the path to records for second and later page responses. Set only when follow-up pages place records at a different location than the first response; leave empty when all pages share the same structure."},"lastPageStatusCode":{"type":"integer","description":"HTTP status code that signals the last page, replacing the default behavior of treating 404 as the end of pagination. When this status is received, paging stops and the response is not treated as an error. Set only when the API uses a non-404 code (such as 204 or 400) to indicate no more pages."},"lastPagePath":{"type":"string","description":"JSON path to a response-body field that signals the end of pagination, such as a \"has more\" flag or a cursor that empties on the last page. Must be used with `lastPageValues`, which lists the values at this path that stop paging. If the path does not exist in a response, the condition is not considered met."},"lastPageValues":{"type":"array","description":"Values at `lastPagePath` that stop pagination; a match on any entry ends paging. All entries are compared as exact, case-sensitive strings, even for boolean or numeric fields — use `\"true\"`, `\"false\"`, `\"null\"` for JSON null, or `\"\"` for an empty string. Required when `lastPagePath` is set.","items":{"type":"string"}},"maxPagePath":{"type":"string","description":"JSON path to the total page count in the response, used to stop paging once the last page is reached. Only applies to the `page` and `skip` methods. Point it at the total number of pages, not the current page number."},"maxCountPath":{"type":"string","description":"JSON path to the total record count in the response, used to stop paging once all records have been retrieved. Only applies to the `page` and `skip` methods; when both are set, `maxPagePath` takes precedence. Point it at the total number of records, not the count in the current page."}},"if":{"properties":{"method":{"const":"body"}},"required":["method"]},"then":{"required":["body"]},"else":{"if":{"properties":{"method":{"const":"token"}},"required":["method"]},"then":{"required":["path","pathLocation"]},"else":{"if":{"properties":{"method":{"const":"relativeuri"}},"required":["method"]},"then":{"required":["relativeURI"]},"else":{"if":{"properties":{"method":{"const":"url"}},"required":["method"]},"then":{"required":["path"]}}}}},"response":{"type":"object","description":"Controls how records are extracted from the API response and how success or failure is detected at the response level. When the API wraps records in an envelope object, set `resourcePath` to the path of the records array — without it, the entire response body is treated as a single record. Leave this object undefined when the API returns a bare JSON array.","properties":{"resourcePath":{"type":"string","description":"Dot-separated path to the array of records inside the response body (e.g. `data.customers` for `{\"data\": {\"customers\": [...]}}`); without it, a wrapped response is treated as a single record. Values starting with `$` are evaluated as JSONPath instead of dot notation — including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); all other values keep the existing dot-notation behavior unchanged. Leave undefined when the API returns a bare JSON array. This extracts records from the API response — not to be confused with `oneToMany`/`pathToMany`, which unwrap arrays from input records, or `paging.resourcePath`, which applies only to subsequent page responses."},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"},"resourceIdPath":{"type":"string","description":"Path to the unique identifier within each record, used primarily when processing results of asynchronous import responses. When omitted, the system looks for standard `id` or `_id` fields automatically."},"successPath":{"type":"string","description":"Path to a response field that signals whether the call succeeded, for APIs that return HTTP 200 even on failure. Must be used with `successValues` to define which values at this path count as success."},"successValues":{"type":"array","items":{"type":"string"},"description":"Values at `successPath` that mark the response as successful; any other value is treated as an error. All comparisons are string-based — use `\"true\"` or `\"false\"` for boolean fields."},"errorPath":{"type":"string","description":"Path to the error message in the response body. The value at this path is included in error logs and error records when the API returns an error."},"failPath":{"type":"string","description":"Path to a response field that signals failure even when the HTTP status code is 200 — the inverse of `successPath`. Must be used with `failValues`."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at `failPath` that mark the response as failed, even when the HTTP status code is 200."},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, treats the value at `successPath` as an array and counts the response as successful if any element matches `successValues`, rather than requiring a single scalar match. Set it for APIs that return per-record status arrays in a batch response."},"twoDArray":{"type":"object","description":"Parsing options for endpoints that return tabular data as a two-dimensional array (rows of cells) rather than an array of objects, such as spreadsheet-style or report APIs.","properties":{"hasHeader":{"type":"boolean","description":"When true, the first row is treated as column headers and used to name the fields of each generated record."},"doNotNormalize":{"type":"boolean","description":"When true, the rows are passed through as raw arrays instead of being normalized into keyed records."}}},"blobFormat":{"type":"string","description":"Controls how the binary response body is decoded for blob exports. Only relevant when `http.type` is `file` or the export type is `blob`.","enum":["utf8","ucs2","utf-16le","ascii","binary","base64","hex"]}}},"_httpConnectorVersionId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector version used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"_httpConnectorResourceId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector resource used by this export. Set by the connector framework; client-supplied values are ignored (write-tested)."},"sendAuthForFileDownloads":{"type":"boolean","description":"When true, includes authentication headers when downloading files."},"_httpConnectorEndpointId":{"type":"string","format":"objectId","readOnly":true,"description":"Identifies the HTTP connector endpoint configuration used for this export's requests. Set by the connector framework; client-supplied values are ignored (write-tested)."}},"if":{"properties":{"type":{"const":"file"}},"required":["type"],"not":{"properties":{"formType":{"const":"assistant"}},"required":["formType"]}},"then":{"required":["file"]}},"Salesforce":{"type":"object","description":"Configuration for Salesforce exports. Required when the export's `_connectionId` references a Salesforce connection; omit for other connection types. The `type` field selects the extraction mode: `soql` runs batch queries and requires the `soql` object, while `distributed` listens for real-time events and requires the `distributed` object. File retrieval (when the export's `type` is `blob`) requires `sObjectType` and `id` instead.","properties":{"type":{"type":"string","description":"Selects the extraction mode and determines which configuration object is required. Use `soql` for scheduled or on-demand batch queries and lookups — it requires the `soql` object and works with both the `rest` and `bulk` APIs and the standard, delta, test, and once export types. Use `distributed` for real-time event handling — it requires the `distributed` object, always appears as a Listener in Flow Builder, ignores the `api` field, and supports only the standard export type.","enum":["soql","distributed"]},"sObjectType":{"type":"string","description":"API name of the Salesforce object the export operates on; the object must exist in the connected org and be accessible to the integration user. Required for distributed exports and for blob exports — blob exports accept only the file storage objects (`Attachment`, `ContentVersion`, `Document`) paired with the `id` field. Optional for SOQL exports, where the object can be inferred from the query."},"id":{"type":"string","description":"Salesforce record ID of the file to retrieve; required for blob exports and not used for `soql` or `distributed` exports. Accepts a static ID or a handlebars expression such as `{{record.Attachment_Id__c}}` to resolve the file at runtime — dynamic IDs require the export to run as a lookup (`isLookup: true`). The ID must belong to the object named in `sObjectType`."},"includeDeletedRecords":{"type":"boolean","description":"When true, SOQL exports use Salesforce's `queryAll()` instead of `query()`, including Recycle Bin records deleted within the past 15 days; each record's `IsDeleted` field identifies deletions. Useful for synchronizing deletes to target systems or maintaining a complete audit trail. Ignored for distributed and blob exports.","default":false},"api":{"type":"string","description":"Salesforce API used to run SOQL queries; ignored for distributed and blob exports. Use `rest` (the default when omitted) for smaller datasets (under 10,000 records) and for lookup exports — the Bulk API is not compatible with `isLookup: true`. Use `bulk` for large data volumes and higher throughput, optionally tuned through the `bulk` object.","enum":["rest","bulk"]},"bulk":{"type":"object","description":"Settings for Salesforce Bulk API 2.0 jobs. Only applies when `api` is `bulk` on a SOQL export; ignored otherwise.","properties":{"maxRecords":{"type":"integer","description":"Caps how many records a single Bulk API job retrieves, which helps prevent timeouts with complex queries or large records. When omitted, Salesforce's default applies. Lower values suit complex or custom objects; higher values improve throughput for simple records.","minimum":10000},"purgeJobAfterExport":{"type":"boolean","default":true,"description":"When true, deletes the Bulk API job in Salesforce after all data is retrieved, keeping the Bulk Data Load Jobs list clean — at the cost of making job details unavailable for later troubleshooting. Has no effect on the data retrieved or the success of the export."}}},"soql":{"type":"object","description":"SOQL query configuration; required when `type` is `soql` and not used otherwise. The query controls which objects, fields, and filter conditions the export retrieves, with either the REST or Bulk API.\n\nRequired when type is soql.","properties":{"query":{"type":"string","description":"SOQL statement passed directly to Salesforce that defines which objects, fields, and records the export retrieves. Supports handlebars — for delta exports, filter with `WHERE LastModifiedDate > {{lastExportDateTime}}` — and relationship queries that fetch parent and child records together. Select only the fields you need and use `ORDER BY` for consistent results across pages.","maxLength":200000}}},"distributed":{"type":"object","description":"Real-time event listener configuration; required when `type` is `distributed` and not used otherwise. The system installs triggers in the connected Salesforce org and delivers records to the flow as create, update, and delete events occur — no scheduling or manual execution is involved.","properties":{"referencedFields":{"type":["array","null"],"description":"Fields from related objects to include in the exported record, written in dot notation (e.g. `Account.Name`, `Owner.Email`, `Custom_Lookup__r.Field__c`). Works with lookup and master-detail relationships, up to 10 unique referenced relationships per export. Referenced fields are retrieved via separate API calls, so include only fields the integration actually needs.","items":{"type":["string","null"]}},"disabled":{"type":"boolean","description":"When true, the listener stops processing events while its configuration and Salesforce triggers stay in place. Events that occur while disabled are ignored, not queued — they are not processed retroactively when re-enabled, so consider a delta export to catch up after extended pauses."},"qualifier":{"type":["string","null"],"description":"Salesforce formula expression that filters which events are processed; when omitted (stored as `null`), all events for the object are processed. Evaluated inside Salesforce before events are sent, which is more efficient than filtering in a later flow step. Reference only fields that exist on the monitored object; formula functions such as `ISCHANGED(Status__c)` are supported."},"batchSize":{"type":["integer","null"],"description":"Controls how many event records are grouped into each real-time processing batch. Stored as `null` when not configured. Smaller batches lower latency for time-sensitive operations; larger batches improve throughput for high-volume objects. Does not limit how many records are processed in total — only how they are grouped.","minimum":4,"maximum":200},"skipExportFieldId":{"type":["string","null"],"description":"API name of a Salesforce checkbox field used to prevent infinite loops in bidirectional syncs: when the integration updates a record, this field is set so the resulting event is ignored, then cleared automatically. Required for bidirectional sync scenarios. The field must be a checkbox dedicated to integration use and updateable by the integration user."},"relatedLists":{"type":["array","null"],"description":"Child record sets to include with the parent record when it changes, one entry per related list. When omitted (stored as `null`), only the primary record is processed. Each related list adds Salesforce API calls and increases payload size.","items":{"type":"object","description":"Defines how to retrieve one type of child record related to the primary object. Configure multiple entries to retrieve different types of children.","properties":{"referencedFields":{"type":"array","description":"API names of the child object fields to retrieve; only the listed fields are included, and an empty array retrieves only the `Id` field. Include only fields the integration needs — each field adds data volume and processing time.","items":{"type":["string","null"]}},"parentField":{"type":"string","description":"API name of the lookup or master-detail field on the child object that references the parent (e.g. `AccountId`, `Parent_Object__c`) — the field's API name, not the relationship name. Used to build the query that fetches children for each parent record."},"sObjectType":{"type":"string","description":"Case-sensitive API name of the child object to retrieve (e.g. `Contact`, `Custom_Child__c`) — use the API name, not the label. The object must have a relationship field to the parent and be accessible to the connected user."},"filter":{"type":"string","description":"SOQL condition that limits which child records are included; when omitted, all related children are retrieved. Provide only the condition expression without the `WHERE` keyword — it is combined automatically with the parent relationship filter."},"orderBy":{"type":"string","description":"Sort order for the retrieved child records, as field names with optional `ASC`/`DESC` directions (e.g. `CreatedDate DESC`). Provide only the fields and directions without the `ORDER BY` keywords. When omitted, Salesforce determines the order."}},"required":["parentField","referencedFields","sObjectType"]}}}}},"if":{"properties":{"type":{"const":"distributed"}},"required":["type"]},"then":{"required":["distributed","sObjectType"]},"else":{"if":{"required":["distributed"]},"then":{},"else":{"if":{"required":["id"]},"then":{"required":["sObjectType"]},"else":{"if":{"not":{"propertyNames":{"enum":["metadata"]}}},"then":{"required":["soql","type"]}}}}},"AS2":{"type":"object","description":"Configures AS2 exports and listeners. Optional — the transport settings live on the AS2\nconnection, and an AS2 export is valid with only `file` (parse settings); set this object\nto link a Trading Partner Connector or to transfer raw files as blobs. An AS2 listener\nacts as the flow's source, receiving trading-partner transmissions in near real-time and\nhandling decryption, signature verification, and MDN generation; AS2 (Applicability\nStatement 2) transmits EDI and other data securely over HTTP/S using S/MIME encryption\nand digital signatures.","properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies the partner-specific EDI configuration —\ncommunication protocol, document schemas, mappings, validation rules, and endpoint\ndetails. Set this to link the export to all settings required for AS2 communication\nwith that partner."},"blob":{"type":"boolean","description":"When true, retrieves raw files without parsing them into structured records (rendered as\na \"Transfer\" step in the flow UI). Use only when the file contents are not needed in\nsubsequent steps — for binary files or when parsing is handled downstream. Only\navailable on AS2 and VAN exports."}},"required":[]},"DynamoDB":{"type":"object","description":"Defines how records are queried from DynamoDB tables. Required when the _connectionId field\nreferences a DynamoDB connection; must not be included for other connection types. Basic\nexports need region, method, tableName, keyConditionExpression, expressionAttributeNames,\nand expressionAttributeValues; once exports (export type \"once\") additionally need\nonceExportPartitionKey, plus onceExportSortKey for composite-key tables.","required":["region","tableName","keyConditionExpression","expressionAttributeNames","expressionAttributeValues"],"properties":{"region":{"type":"string","enum":["us-east-1","us-east-2","us-west-1","us-west-2","af-south-1","ap-east-1","ap-south-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-southeast-1","ap-southeast-2","ca-central-1","eu-central-1","eu-west-1","eu-west-2","eu-west-3","eu-south-1","eu-north-1","me-south-1","sa-east-1"],"description":"AWS region hosting the DynamoDB table. Must match the region where the table is\ndeployed so the integration can reach it.","default":"us-east-1"},"method":{"type":"string","enum":["query"],"description":"DynamoDB operation used to retrieve items. Only \"query\" is currently supported."},"tableName":{"type":"string","description":"Name of the DynamoDB table to query. Must exactly match an existing table (case-sensitive)."},"keyConditionExpression":{"type":"string","description":"Key condition determining which items the query retrieves. Must include a condition on\nthe partition key and may add sort-key conditions (equality, BETWEEN, begins_with).\nReference attribute names with \"#\" placeholders defined in expressionAttributeNames and\nvalues with \":\" placeholders defined in expressionAttributeValues."},"filterExpression":{"type":"string","description":"Filters query results on non-key attributes after the key condition is applied; omit to\nreturn all items matching the key condition. Uses the same \"#\" and \":\" placeholders\ndefined in expressionAttributeNames and expressionAttributeValues."},"projectionExpression":{"type":"array","items":{"type":"string"},"description":"Attributes to return from each item, reducing data transfer; omit to return all\nattributes. Each array element is one field, referenced via \"#\" placeholders defined in\nexpressionAttributeNames."},"expressionAttributeNames":{"type":"string","description":"JSON string mapping \"#\" placeholders to actual attribute names, e.g.\n{\"#pk\": \"customerId\"}. Placeholders defined here are used in keyConditionExpression,\nfilterExpression, and projectionExpression."},"expressionAttributeValues":{"type":"string","description":"JSON string mapping \":\" placeholders to comparison values, e.g. {\":status\": \"ACTIVE\"}.\nValues can be static or dynamic handlebars expressions such as {{lastExportDateTime}},\nand are referenced from keyConditionExpression and filterExpression."},"onceExportPartitionKey":{"type":"string","description":"Partition key attribute that uniquely identifies items when the export's type is \"once\".\nCeligo uses it to mark items as processed after a successful export, preventing the same\nitems from being exported again on subsequent runs."},"onceExportSortKey":{"type":"string","description":"Sort key attribute used together with onceExportPartitionKey to identify processed items\nwhen the table has a composite primary key. Omit for tables keyed by a partition key\nalone."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"PathToRecords":{"type":"string","maxLength":250,"description":"Path to the array of records inside each document or item fetched from the source; each array element is emitted as an individual record, which keeps records within the 5 MB page-size limit even when the source document exceeds it. Accepts dot notation (e.g. `data.orders`) or JSONPath for values starting with `$`, including unions (`$['orders','invoices'][*]`) and filter expressions (`$.items[?(@.qty>3)]`); a path that resolves to nothing emits zero records for that document or item. When omitted, each document or item is emitted as one record, exactly as before — HTTP and file-based exports configure this same capability through their existing `http.response.resourcePath` and `file.json`/`file.xml` `resourcePath` fields."},"FTP":{"type":"object","description":"Defines which files to retrieve from an FTP, FTPS, or SFTP server. Required when the\n_connectionId field references an FTP/SFTP connection; must not be included for other\nconnection types. directoryPath selects the folder, fileNameStartsWith/fileNameEndsWith\nfilter files by name, and backupDirectoryPath controls where files are moved after\nretrieval.","required":["directoryPath"],"properties":{"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading Partner Connector that supplies partner-specific B2B settings for this export.\nWhen set, the export inherits the connector's pre-configured settings; omit to use only\nthe FTP connection details."},"directoryPath":{"type":"string","description":"Directory on the server to retrieve files from, either absolute or relative to the login\ndirectory; the FTP user must have read permission on it. Use forward slashes regardless\nof server OS — paths are case-sensitive on UNIX/Linux servers. Supports handlebars\ntemplates, e.g. archive/{{date 'YYYY-MM-DD'}}."},"fileNameStartsWith":{"type":"string","description":"Only retrieves files whose names start with this value (case-sensitive on most servers);\naccepts static text or handlebars templates. When combined with fileNameEndsWith, files\nmust match both."},"fileNameEndsWith":{"type":"string","description":"Only retrieves files whose names end with this value, commonly a file extension\n(case-sensitive on most servers). When combined with fileNameStartsWith, files must\nmatch both."},"backupDirectoryPath":{"type":"string","description":"Directory on the same server where files are moved after successful export, giving you\nan independent backup; if omitted, files are simply deleted from the source directory\nafter successful export (Celigo also keeps its own copy of processed files for a set\nperiod). Supports static paths or handlebars templates."}}},"JDBC":{"type":"object","description":"Configuration object for JDBC (Java Database Connectivity) data integration exports.\n\nThis object is REQUIRED when the _connectionId field references a JDBC database connection\nand must not be included for other connection types. It defines how data is extracted\nfrom relational databases using SQL queries.\n\n**Jdbc export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - **ALWAYS REQUIRED** - The SQL SELECT statement\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `jdbc`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `jdbc.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"jdbc\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```","required":["query"],"properties":{"formType":{"type":["string","null"],"enum":["sql","simple",null],"description":"Selects how the export's query is authored. Use `sql` for a hand-written SQL statement in\n`query`; use `simple` to build the query from the `simple` object's table/columns/filter."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins and\naggregations. For delta exports, include {{lastExportDateTime}}/{{currentExportDateTime}}\nin the WHERE clause rather than configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}},"simple":{"type":"object","description":"Visual query-builder configuration used when `formType` is `simple`; the platform builds\nthe SELECT from these instead of raw SQL. Only relevant when `formType` is `simple`.","properties":{"table":{"type":"string","description":"Table or view to select rows from."},"columns":{"type":"array","items":{"type":"string"},"description":"Columns to return; an empty list selects all columns."},"filter":{"description":"Filter applied as the WHERE clause for the generated query, stored as the\nplatform's structured filter-rules object.","allOf":[{"$ref":"#/components/schemas/Filter"}]}}}}},"MongoDB":{"type":"object","description":"Defines how documents are retrieved from MongoDB collections. Required when the\n_connectionId field references a MongoDB connection; must not be included for other\nconnection types. Supports find queries with optional filter criteria and field projections.","required":["collection"],"properties":{"method":{"type":"string","enum":["find"],"description":"MongoDB operation used to retrieve documents. Only \"find\" is currently supported,\nequivalent to db.collection.find(filter, projection)."},"collection":{"type":"string","description":"Name of the MongoDB collection to query. Case-sensitive and must reference an existing\ncollection in the connected database."},"filter":{"type":"string","description":"MongoDB query document, as a JSON string, that selects which documents to export; omit\nto return every document in the collection. Supports standard MongoDB query operators\nand handlebars variables for dynamic values — for example\n{\"lastModified\": {\"$gt\": \"{{lastRun}}\"}} for incremental processing."},"projection":{"type":"string","description":"MongoDB projection document, as a JSON string, that limits which fields are returned;\nomit to return all fields. Use 1 to include fields or 0 to exclude them — the two modes\ncannot be mixed except for _id, which is included by default unless explicitly excluded.\nProjection affects only the shape of returned documents, not which documents match."},"pipeline":{"type":"string","description":"MongoDB aggregation pipeline, as a JSON-array string of stages, used instead of a plain\nfind when documents need to be transformed, joined, or grouped server-side (e.g. `$match`,\n`$lookup`, `$group`). When set, it takes the place of `filter`/`projection`. Supports\nhandlebars variables for incremental processing."},"readPreference":{"type":"string","enum":["doNotOverride","primary","primaryPreferred","secondary","secondaryPreferred","nearest"],"default":"doNotOverride","description":"Overrides which replica-set member this export reads from, trading consistency for load\ndistribution. Leave at `doNotOverride` to inherit the connection's setting."},"pathToRecords":{"$ref":"#/components/schemas/PathToRecords"},"includeParentData":{"$ref":"#/components/schemas/IncludeParentData"}}},"NetSuite":{"type":"object","description":"NetSuite-specific export configuration. Required when `_connectionId` references a NetSuite\nconnection; omit for all other connection types. Supports saved-search, RESTlet, and\ndistributed (SuiteApp) exports, plus two file cabinet modes: blob exports transfer files\nas-is (set the export's top-level `type` to `blob` and configure `netsuite.blob`), while\nfile exports parse file contents into records (leave the export's top-level `type` unset\nand configure `netsuite.file`).","properties":{"type":{"type":"string","enum":["search","basicSearch","metadata","selectoption","restlet","getList","getServerTime","distributed","file"],"description":"Controls how data is retrieved from NetSuite and which sibling object must be configured:\n`search` pairs with `netsuite.searches`, `restlet` with `netsuite.restlet`, `distributed`\nwith `netsuite.distributed`, and `file` with `netsuite.file.folderInternalId`. For blob\nexports (raw file transfer without parsing), leave this field unset, set the export's\ntop-level `type` to `blob`, and configure `netsuite.internalId` instead. For lookups\n(`isLookup: true`), prefer `restlet`, which supports `suiteapp2.0` saved searches with\ndynamic inputs; `search` is limited for dynamic lookups."},"searches":{"type":"array","description":"Saved search configurations that query NetSuite for records. Each entry references a\nsaved search by internal ID, names the record type being searched, and can add filter\ncriteria.","items":{"type":"object","properties":{"savedSearchId":{"type":"string","description":"Internal ID of the NetSuite saved search to run."},"recordType":{"type":"string","description":"NetSuite record type being searched, as its exact lowercase script ID\n(e.g. \"customer\", \"salesorder\") — not the display name."},"criteria":{"type":"array","description":"Additional filter criteria applied on top of the saved search.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on.  REQUIRED.\nMust come from the record type's SEARCH COLUMNS list\n(NOT the body-fields list).  Becomes the `name`\nargument of NetSuite's `search.createFilter()`."},"operator":{"type":"string","description":"Comparison operator.  REQUIRED.  Supported values\ndepend on the column's data type (e.g. `is`,\n`isnot`, `after`, `before`, `anyof`,\n`noneof`, `contains`, `startswith`,\n`greaterthan`, `lessthan`).  Must be a string\nNetSuite recognises -- mismatched operators cause\nruntime rejection."},"join":{"type":"string","description":"Optional join name when filtering through a related\nrecord (e.g. `customer` from a sales order).  Use\nonly when the column lives on a related record and\nNetSuite supports the join from the base record type."},"searchValue":{"description":"Value (or array of values for `anyof`-style\noperators) to compare against the column.  Required\nfor most operators; omit for the few unary operators\n(e.g. `isempty`, `isnotempty`)."}},"required":["field","operator"]}}}}},"metadata":{"type":"object","description":"Supplemental metadata associated with the NetSuite export."},"selectoption":{"type":"object","description":"Configuration for `selectoption` exports, which retrieve the available select options\nfor a NetSuite field."},"customFieldMetadata":{"type":"object","description":"Metadata describing the custom fields defined in the NetSuite account."},"skipGrouping":{"type":"boolean","description":"When true, each result row is processed individually instead of being aggregated with\nrelated rows. When false or omitted, related rows are grouped before processing."},"statsOnly":{"type":"boolean","description":"When true, returns only summary statistics about matching records instead of the\ndetailed records themselves."},"internalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet to export. Required for blob\nexports (the export's top-level `type` is `blob`); the file is transferred as-is\nwithout parsing. For parsed file exports, use `netsuite.file.folderInternalId` instead."},"blob":{"type":"object","properties":{"purgeFileAfterExport":{"type":"boolean","description":"When true, permanently deletes the file from the NetSuite file cabinet after a\nsuccessful export. When false or omitted, the file is left in place."}},"description":"Configuration for blob exports, which transfer files from the NetSuite file cabinet\nas-is without parsing them into records. To export a blob, set the export's top-level\n`type` to `blob`, set `netsuite.internalId` to the file's internal ID, and leave\n`netsuite.type` unset. Use `netsuite.file` instead when file contents should be parsed\ninto records."},"restlet":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the RESTlet operates on, as its script ID. Custom record\ntypes use the \"customrecord_\" prefix."},"batchSize":{"type":"number","description":"Number of records the RESTlet returns per request (default 1000). This, not the\nexport's `pageSize`, sizes each NetSuite call; the export keeps requesting until the\nsearch is exhausted. Larger batches reduce round-trips but raise NetSuite governance\nand memory use per call; tune to the record's size. In a test run or preview the\nrequest is capped at the export's `pageSize` (default 20) instead."},"searchId":{"type":["string","null"],"description":"Internal ID of the NetSuite saved search the RESTlet executes. Results follow the\nsaved search's current definition, so editing the search in NetSuite changes the\nexport output without changing this ID."},"useSS2Restlets":{"type":"boolean","description":"When true, calls SuiteScript 2.0 RESTlets. When false or omitted, legacy\nSuiteScript 1.0 RESTlets are used.\nSet at step creation together with restletVersion — the same\ncreation-time-only constraint applies (see restletVersion)."},"restletVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"RESTlet version the export invokes. Defaults to `suiteapp2.0` when\n`useSS2Restlets` is true, `suitebundle` otherwise.\nThe version is fixed when the step is created — the Advanced selector is\ndisabled on existing steps, and migrating an existing export to a\ndifferent version means recreating or cloning it."},"criteria":{"type":"array","description":"Filter conditions added on top of the saved search (the UI's \"Additional search\ncriteria\"). Each condition pairs a search column with an operator and one or two\ncomparison values, and the conditions are combined with AND — every one must match.","items":{"type":"object","properties":{"field":{"type":"string","description":"Script-id of the search column to filter on. This is the primary\nfield the criterion is evaluated against (e.g. \"trandate\", \"status\")."},"join":{"type":"string","description":"Join relationship that applies this filter to a related record's fields instead\nof the base record. Must match a join name NetSuite defines for the record type."},"operator":{"type":"string","enum":["after","allof","any","anyof","before","between","contains","doesnotcontain","doesnotstartwith","equalto","greaterthan","greaterthanorequalto","haskeywords","is","isempty","isnot","isnotempty","lessthan","lessthanorequalto","noneof","notafter","notallof","notbefore","notbetween","notequalto","notgreaterthan","notlessthan","notlessthanorequalto","noton","notonorafter","notonorbefore","notwithin","on","onorafter","onorbefore","startswith","within"],"description":"Comparison operator applied between the column and the search value, using\nNetSuite's lowercase search operator names. Which operators a column accepts\ndepends on its data type."},"searchValue":{"description":"Value the column is compared against — a string, a number, or an array of\nvalues for `anyof`-style operators. On lookup steps it may be a Handlebars\nexpression rendered from the incoming record (for example `{{poNumber}}`)."},"searchValue2":{"description":"Second comparison value for the two-value operators `between` and `notbetween`\n(the upper bound). Omit for every other operator."},"formula":{"type":"string","description":"NetSuite formula expression used as the filter condition, for criteria that\nstandard field-operator-value comparisons can't express."}}}},"columns":{"type":"array","description":"Search columns the RESTlet returns for each matching record. With a saved search,\nomit this to return the search's own result columns; an ad-hoc search (no\n`searchId`) must list its columns here.","items":{"type":"object","properties":{"_id":{"type":"string","readOnly":true,"description":"Subdocument id the server assigns to the column entry on save. Not a NetSuite\nfield id — never set it when authoring."},"name":{"type":"string","description":"Column field name as referenced in the search."},"join":{"type":"string","description":"Join relationship that sources this column from a related record instead of\nthe base record. Supports dot notation for nested joins (e.g. \"employee.manager\")."},"summary":{"type":"string","enum":["group","sum","count","avg","min","max"],"description":"Summary type applied to this column, turning the search into a summary search."},"formula":{"type":"string","description":"NetSuite formula expression that computes this column's value at runtime, such\nas a CASE statement or date formatting, instead of reading a stored field."},"label":{"type":"string","description":"Display name for the column; it becomes the property name of the column's value\nin each exported record."},"sort":{"type":"boolean","description":"When true, query results are sorted by this column's values."}}}},"markExportedBatchSize":{"type":"integer","description":"Number of records updated per RESTlet call when marking records as exported in\nNetSuite (live: an integer count, e.g. 100).","maximum":100,"minimum":1},"hooks":{"type":["object","null"],"properties":{"batchSize":{"type":"number","description":"Legacy location of the RESTlet page size; `restlet.batchSize` is the current\nfield and takes precedence when both are set."},"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the JavaScript file in the NetSuite File Cabinet that defines\nthe hook function. Must be readable by the role behind the export's connection."},"function":{"type":"string","description":"Name of the global function in that file that NetSuite invokes as the pre\nsend hook."},"configuration":{"type":"object","description":"Free-form JSON stored with the hook reference for the script's own use. Custom\nsettings in scope for the export are passed to the function separately as\n`options.settings`."}},"description":"SuiteScript hook that runs inside NetSuite after a page of records is collected\nand before it is sent to the Celigo platform."}},"description":"SuiteScript hooks for the export. Only `preSend` exists on exports; imports carry\nthe pre map, post map, and post submit hooks."},"cLocked":{"type":"object","description":"Lock state that prevents modification of the configuration when set."}},"description":"Configuration for `restlet` exports. Identifies the RESTlet script that retrieves data\nfrom NetSuite, along with the saved search, criteria, and columns it executes with."},"distributed":{"type":"object","properties":{"recordType":{"type":"string","description":"NetSuite record type the distributed export listens to, as its exact lowercase\nscript ID (e.g. \"customer\", \"salesorder\") — not the display name. Custom record\ntypes use the \"customrecord_\" prefix."},"executionContext":{"type":"array","description":"NetSuite execution contexts that trigger this distributed export. A record change\nfires the export only when it occurs in one of the listed contexts.","default":["userinterface","webstore"],"items":{"type":"string","enum":["userinterface","webservices","csvimport","offlineclient","portlet","scheduled","suitelet","custommassupdate","workflow","webstore","userevent","mapreduce","restlet","webapplication","restwebservices"]}},"disabled":{"type":"boolean","description":"When true, disables the distributed export so record changes no longer trigger it.\nWhen false or omitted, the export remains active."},"executionType":{"type":"array","description":"Record operations that trigger this distributed export. A record event fires the\nexport only when its operation matches one of the listed types.","default":["create","edit","xedit"],"items":{"type":"string","enum":["create","edit","delete","xedit","copy","view","cancel","approve","reject","pack","ship","markcomplete","reassign","editforecast","dropship","specialorder","orderitems","paybills","print","email"]}},"qualifier":{"type":["array","string","null"],"description":"Qualification criteria that further restrict which record changes the distributed\nexport processes. Stored either as a filter-expression array (current format), a\nlegacy expression string, or null when no qualifier is set."},"skipExportFieldId":{"type":"string","description":"ID of the NetSuite field used to flag records that should be skipped during export.\nOnly affects export output; the data remains unchanged in NetSuite."},"hooks":{"type":"object","properties":{"preSend":{"type":"object","properties":{"fileInternalId":{"type":"string","description":"Internal ID of the file in the NetSuite file cabinet that the preSend hook references."},"function":{"type":"string","description":"Name of the function invoked as the preSend hook. The function can validate\nor modify the payload before it is sent."},"configuration":{"type":"object","description":"Settings that control the preSend hook's behavior."}},"description":"Hook invoked immediately before the payload is sent, allowing custom\nprocessing, modification, or validation."}},"description":"Custom hook functions executed at defined points in the distributed export lifecycle."},"sublists":{"type":["array","null"],"items":{"type":"string"},"description":"IDs of the NetSuite sublists to include with each exported record (for\nexample `item` for transaction line items). Records are exported with\nbody fields only when no sublists are selected. Legacy documents may\nstore null (equivalent to no sublists)."},"referencedFields":{"type":"object","description":"Field identifiers referenced by the distributed export."},"relatedLists":{"type":"object","description":"Related record lists associated with the exported NetSuite record."},"forceReload":{"type":"boolean","description":"When true, bypasses cached data and reloads directly from the source."},"ioEnvironment":{"type":"string","description":"integrator.io environment the distributed NetSuite bundle communicates with. Live-observed values include `production` and `staging`."},"ioDomain":{"type":"string","description":"integrator.io domain the distributed NetSuite bundle calls back to (e.g.\n`integrator.io`). Live-observed on distributed exports."},"lastSyncedDate":{"type":"string","format":"date-time","description":"Timestamp when the distributed export last completed a successful synchronization.\nNot set until the first successful sync."},"settings":{"type":"object","description":"Additional key-value configuration settings for the distributed export."},"useSS2Framework":{"type":"boolean","description":"When true, the distributed export runs on the SuiteScript 2.0 framework. When\nfalse or omitted, the legacy SuiteScript 1.0 framework is used.\nSet at step creation together with frameworkVersion — the same\ncreation-time-only constraint applies (see frameworkVersion)."},"frameworkVersion":{"type":"string","enum":["suitebundle","suiteapp1.0","suiteapp2.0"],"description":"SuiteApp framework version used by the distributed export.\nFixed when the step is created — the Advanced selector is disabled on\nexisting steps, and migrating an existing listener to a different\nversion means recreating or cloning it."}},"description":"Configuration for `distributed` exports, which use the NetSuite SuiteApp to fire\nreal-time, event-driven exports when records change. Define the record type to listen\nto and the execution contexts and operations that trigger it."},"getList":{"type":"array","description":"Configuration for `getList` exports — a list of record references, each retrieving one\nNetSuite record by its identifier. The export returns the fetched records in list order.","items":{"type":"object","properties":{"type":{"type":"string","description":"Standard NetSuite record type to retrieve (e.g. \"customer\", \"salesOrder\").\nUsed when `typeId` is absent. Case-sensitive."},"typeId":{"type":"string","description":"Script ID of a custom record type (\"customrecord_...\") or custom transaction\ntype (\"customtransaction_...\"). Takes precedence over `type` when present.\nCase-sensitive."},"internalId":{"type":"string","description":"Internal ID of the NetSuite record to retrieve. Assigned by NetSuite at record\ncreation and unique within the record type. Takes precedence over `externalId`."},"externalId":{"type":"string","description":"Identifier assigned by an external system, used to reference and synchronize the\nrecord across systems. Distinct from the NetSuite-assigned internal ID."}}}},"searchPreferences":{"type":"object","properties":{"bodyFieldsOnly":{"type":"boolean","description":"When true, search results include only the record's body fields and exclude fields\nfrom joined or related records. Reduces payload size when related data isn't needed."},"pageSize":{"type":"number","description":"Number of search results NetSuite returns per page."},"returnSearchColumns":{"type":"boolean","description":"When true, search results include the column data defined in the search. When\nfalse, column data is omitted and results contain only minimal record information."}},"description":"Preferences that control how NetSuite executes searches and shapes the results it returns."},"file":{"type":"object","description":"Configuration for file exports, which retrieve files from the NetSuite file cabinet\nand parse their contents (CSV, XML, JSON) into records. Leave the export's top-level\n`type` unset when using this object; for raw transfers without parsing, use\n`netsuite.blob` with the export's `type` set to `blob` instead.","properties":{"folderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder to export files from. Accepts a\nhandlebars expression (e.g. `{{record.folderId}}`) when the folder must be\nselected dynamically from record data. The ID is stable across folder renames and\nmoves, but may differ between non-production and production accounts."},"backupFolderInternalId":{"type":"string","description":"Internal ID of the NetSuite file cabinet folder where backup files are stored.\nIDs are account-specific and do not transfer between non-production and production\nenvironments."},"fileNameStartsWith":{"type":"string","description":"Optional prefix filter. Only files whose names start with this string are\nexported from the configured folder."},"fileNameEndsWith":{"type":"string","description":"Optional suffix filter. Only files whose names end with this string (e.g. a\n\".csv\" extension) are exported from the configured folder."}}}},"required":[]},"RDBMS":{"type":"object","description":"Configuration object for Relational Database Management System (RDBMS) data integration exports.\n\nThis object defines how data is read from a relational database and must not be included\nfor other connection types. For query-type exports (standard, delta, once) it is REQUIRED\nwhen the _connectionId field references an RDBMS database connection and holds the SQL\nquery. For real-time stream listeners (`type: \"stream\"`) it holds the CDC watch list\n(`tables`) instead — and a PostgreSQL listener scoped by a publication\n(`cdc.publicationName`) may omit this object entirely.\n\n**Rdbms export capabilities**\n- Execute custom SQL SELECT statements\n- Support for joins, aggregations, and functions\n- Flexible data retrieval from any accessible tables or views\n- Compatible with all major database systems\n\n**Critical:** WHAT BELONGS IN THIS OBJECT\n- `query` - The SQL SELECT statement - required for every query-type export (standard, delta, once)\n- `once` - **REQUIRED** when the export's Object Type is `\"once\"` (set _include_once: true)\n- `tables` - the CDC listener watch list - real-time stream listeners (`type: \"stream\"`) only\n- **DO NOT** put `delta` inside this object - delta is handled via the query\n- **DO NOT** author `query` on a stream listener - real-time CDC exports have no SQL query\n\n**Delta exports (type: \"delta\")**\nFor delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.\nInstead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:\n```json\n{\n  \"type\": \"delta\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}\"\n  }\n}\n```\n\n**Once exports (type: \"once\")**\nFor once exports (mark records as processed), populate `rdbms.once.query`:\n```json\n{\n  \"type\": \"once\",\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE exported = false\",\n    \"once\": {\n      \"query\": \"UPDATE customers SET exported = true WHERE id = {{record.id}}\"\n    }\n  }\n}\n```\n\n**Standard exports (type: null or not specified)**\nJust provide the query:\n```json\n{\n  \"rdbms\": {\n    \"query\": \"SELECT * FROM customers WHERE status = 'ACTIVE'\"\n  }\n}\n```\n\n**Real-time CDC listener exports (type: \"stream\")**\nSQL Server and PostgreSQL connections support change-data-capture listeners that stream row\nchanges continuously (the `cdc` object holds the listener settings). A stream export has NO\n`query` — it watches `tables`:\n```json\n{\n  \"type\": \"stream\",\n  \"rdbms\": { \"tables\": \"public.orders,public.customers\" },\n  \"cdc\": { \"properties\": [{ \"name\": \"snapshot.mode\", \"value\": \"no_data\" }] }\n}\n```\nA PostgreSQL listener can instead scope tables through a publication\n(`cdc.publicationName`), in which case `tables` stays unset and the `rdbms` object may be\nomitted entirely.","properties":{"tables":{"type":"string","description":"Comma-separated list of tables the CDC listener watches for changes. Used only by real-time\nlistener exports (`type` is `stream`); standard SQL exports use `query` instead. SQL Server\nlisteners use fully-qualified three-part names (`database.schema.table`); PostgreSQL\nlisteners use two-part names (`schema.table`)."},"query":{"type":"string","description":"SQL SELECT statement executed to retrieve data, from simple table selections to joins,\naggregations, and parameterized queries with Handlebars expressions. Query-type exports\nonly — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,\nreference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather\nthan configuring a separate delta object."},"once":{"type":"object","description":"**CRITICAL: REQUIRED when the export's Object Type is \"once\".**\n\nIf Object Type is \"once\", you MUST set _include_once to true (or include this object).\n\nThis object has ONLY ONE property: \"query\" (a SQL UPDATE string).\nDO NOT create any other properties like \"update\", \"table\", \"set\", \"where\", etc.\n\nCORRECT format:\n```json\n{\"query\": \"UPDATE customers SET exported=true WHERE id={{record.id}}\"}\n```\n\nWRONG format (DO NOT DO THIS):\n```json\n{\"update\": {\"table\": \"customers\", \"set\": {...}}}\n```\n","properties":{"query":{"type":"string","description":"**REQUIRED** - A SQL UPDATE statement string to mark records as processed.\n\nThis is a plain SQL UPDATE query string, NOT a structured object.\n\nThe query runs AFTER each record is successfully exported, setting a flag\nto indicate the record has been processed.\n\nFormat: \"UPDATE <table> SET <column>=<value> WHERE <id_column>={{record.<id_field>}}\"\n\nExample: \"UPDATE customers SET exported=true WHERE id={{record.id}}\"\n\nThe {{record.id}} placeholder is replaced with the actual record ID from each exported row.\n"}}}}},"S3":{"type":"object","description":"Defines which files to retrieve from an Amazon S3 bucket. Required when the _connectionId\nfield references an AWS S3 connection; must not be included for other connection types.\nregion and bucket locate the source, keyStartsWith/keyEndsWith filter objects by key, and\nbackupBucket with keyPrefix controls where files are moved after retrieval.","required":["region","bucket"],"properties":{"region":{"type":"string","default":"us-east-1","description":"AWS region where the bucket is located. Case-insensitive; the value is normalized to\nlowercase."},"bucket":{"type":"string","description":"S3 bucket to retrieve files from. The connection's AWS credentials must have\ns3:ListBucket and s3:GetObject permissions on it."},"keyStartsWith":{"type":"string","description":"Only retrieves objects whose keys start with this value (case-sensitive), effectively\nselecting a folder in S3's flat key structure. When combined with keyEndsWith, objects\nmust match both."},"keyEndsWith":{"type":"string","description":"Only retrieves objects whose keys end with this value (case-sensitive), commonly a file\nextension. When combined with keyStartsWith, objects must match both."},"backupBucket":{"type":"string","description":"Bucket in the same region where files are moved after successful export, giving you an\nindependent backup; if omitted, files are simply deleted from the source bucket after\nsuccessful export (Celigo also keeps its own copy of processed files for a set period).\nThe connection's AWS credentials must have s3:PutObject permission on this bucket."},"keyPrefix":{"type":"string","description":"Prefix prepended to each file's name when it is moved to the backup bucket; accepts\nstatic text or handlebars templates. The original directory structure is not preserved —\nonly the filename is appended to this prefix. Ignored unless backupBucket is set."}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper exports, which delegate data retrieval to custom connector code\n(typically a stack-hosted function) rather than a built-in adaptor. Required when the\n_connectionId field references a wrapper connection.","required":["function"],"properties":{"function":{"type":"string","description":"Name of the function the wrapper invokes to retrieve records. Must match a callable\nfunction in the wrapper's execution context; names are case-sensitive."},"configuration":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"array","maxItems":0}],"description":"Free-form settings passed to the wrapper function at runtime (connector-specific keys such\nas method, apiVersion, headers, relativePath, or body). Structure is defined by the wrapper\ncode, not by this schema. May be stored as an empty array when no settings exist."}}},"Parsers":{"type":"array","description":"Configuration for parsing XML payloads (i.e. files, HTTP responses, etc.). Use this field when you need to process XML data\nand transform it into a JSON records.\n\n**Implementation notes**\n\n- This is where you configure how to parse XML data in your resource\n- Although defined as an array, you typically only need a single parser configuration\n- Currently only XML parsing is supported\n- Only configure this field when working with XML data that needs structured parsing\n","items":{"type":"object","properties":{"version":{"type":"string","description":"Version identifier for the parser configuration format. Currently only version \"1\" is supported.\n\nAlways set this field to \"1\" as it's the only supported version at this time.\n","enum":["1"]},"type":{"type":"string","description":"Defines the type of parser to use. Currently only \"xml\" is supported.\n\nWhile the system is designed to potentially support multiple parser types in the future,\nat this time only XML parsing is implemented, so this field must be set to \"xml\".\n","enum":["xml"]},"name":{"type":"string","description":"Optional identifier for the parser configuration. This field is primarily for documentation\npurposes and is not functionally used by the system.\n\nThis field can be omitted in most cases as it's not required for parser functionality.\n"},"rules":{"type":"object","description":"Configuration rules that determine how XML data is parsed and converted to JSON.\nThese settings control the structure and format of the resulting JSON records.\n\n**Parsing options**\n\nThere are two main parsing strategies available:\n- **Automatic parsing**: Simple but produces more complex output\n- **Custom parsing**: More control over the resulting JSON structure\n","properties":{"V0_json":{"type":"boolean","description":"Controls the XML parsing strategy.\n\n- When set to **true** (Automatic): XML data is automatically converted to JSON without\n  additional configuration. This is simpler to set up but typically produces more complex\n  and deeply nested JSON that may be harder to work with.\n\n- When set to **false** (Custom): Gives you more control over how the XML is converted to JSON.\n  This requires additional configuration (like listNodes) but produces cleaner, more\n  predictable JSON output.\n\nMost implementations use the Custom approach (false) for better control over the output format.\n"},"listNodes":{"type":"array","description":"Specifies which XML nodes should be treated as arrays (lists) in the output JSON.\n\nIt's not always possible to automatically determine if an XML node should be a single value\nor an array. Use this field to explicitly identify nodes that should be treated as arrays,\neven if they appear only once in the XML.\n\nEach entry should be a simplified XPath expression pointing to the node that should be\ntreated as an array.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"includeNodes":{"type":"array","description":"Limits which XML nodes are included in the output JSON.\n\nFor large XML documents, you can use this field to extract only the nodes you need,\nreducing the size and complexity of the resulting JSON. Only nodes specified here\n(and their children) will be included in the output.\n\nEach entry should be a simplified XPath expression pointing to nodes to include.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"excludeNodes":{"type":"array","description":"Specifies which XML nodes should be excluded from the output JSON.\n\nSometimes it's easier to specify which nodes to exclude rather than which to include.\nUse this field to identify nodes that should be omitted from the output JSON.\n\nEach entry should be a simplified XPath expression pointing to nodes to exclude.\n\nOnly relevant when V0_json is set to false (Custom parsing).\n","items":{"type":"string"}},"stripNewLineChars":{"type":"boolean","description":"Controls whether newline characters are removed from text values.\n\nWhen set to true, all newline characters (\\n, \\r, etc.) will be removed from\ntext content in the XML before conversion to JSON.\n","default":false},"trimSpaces":{"type":"boolean","description":"Controls whether leading and trailing whitespace is trimmed from text values.\n\nWhen set to true, all values will have leading and trailing whitespace removed\nbefore conversion to JSON.\n","default":false},"attributePrefix":{"type":"string","description":"Specifies a character sequence to prepend to XML attribute names when converted to JSON properties.\n\nIn XML, both elements and attributes can exist at the same level, but in JSON this distinction is lost.\nTo maintain the distinction between element data and attribute data in the resulting JSON, this prefix\nis added to attribute names during conversion.\n\nFor example, with attributePrefix set to \"Att-\" and an XML element like:\n```xml\n<product id=\"123\">Laptop</product>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"product\": \"Laptop\",\n  \"Att-id\": \"123\"\n}\n```\n\nThis helps maintain the distinction between element content and attribute values in the\nconverted JSON, making it easier to reference specific data in downstream processing steps.\n"},"textNodeName":{"type":"string","description":"Specifies the property name to use for element text content when an element has both\ntext content and child elements or attributes.\n\nWhen an XML element contains both text content and other nested elements or attributes,\nthis field determines what property name will hold the text content in the resulting JSON.\n\nFor example, with textNodeName set to \"value\" and an XML element like:\n```xml\n<item id=\"123\">\n  Laptop\n  <category>Electronics</category>\n</item>\n```\n\nThe resulting JSON would be:\n```json\n{\n  \"item\": {\n    \"value\": \"Laptop\",\n    \"category\": \"Electronics\",\n    \"id\": \"123\"\n  }\n}\n```\n\nThis allows for unambiguous parsing of complex XML structures that mix text content with\nchild elements. Choose a name that's unlikely to conflict with actual element names in your XML.\n"}}}}}},"Mappings":{"type":"array","description":"Array of field mapping configurations for transforming data from one format into another.\n\n**Guidance**\n\nThis schema is designed around RECURSION as its core architectural principle. Understanding this recursive\nnature is essential for building effective mappings:\n\n1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure\n2. Complex data structures (nested objects, arrays of objects, arrays of arrays of objects) are ALL\n   handled through this recursive pattern\n3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings\n\nWhen generating mappings programmatically:\n- For simple fields (string, number, boolean): Create single mapping objects\n- For objects: Create a parent mapping with nested 'mappings' array containing child field mappings\n- For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and\n  recursive 'mappings' to define object structures\n\nThe system will process these nested structures recursively during runtime, ensuring proper construction\nof complex hierarchical data while maintaining excellent performance.\n","items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]}},"items":{"type":"object","properties":{"generate":{"type":"string","description":"**Purpose**\nDefines the target field name in the output object/record.\n\n**Guidance**\nThis is the PRIMARY FIELD that identifies the output property being created:\n\n- For regular fields: Set to the exact property name (e.g., \"firstName\", \"price\", \"isActive\")\n- For object fields: Set to the object property name, then add child mappings in the 'mappings' array\n- For array fields: Set to the array property name, then configure 'buildArrayHelper'\n- For arrays within arrays: Leave EMPTY for the inner array mappings, as they don't have field names\n\nIMPORTANT: Do NOT use dot notation (e.g., \"customer.firstName\") in this field. Instead, create proper\nhierarchical structure with nested mappings:\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"status\": \"Active\",\n  \"mappings\": [\n    {\"generate\": \"firstName\", \"dataType\": \"string\", \"extract\": \"$.name.first\", \"status\": \"Active\"}\n  ]\n}\n```\n\nWhen parsing existing mappings, empty 'generate' fields almost always indicate inner array structures\nwithin a parent array.\n"},"dataType":{"type":"string","description":"**Purpose**\nExplicitly declares the data type of the output field, controlling how data is processed and structured.\n\n**Guidance**\nThis is a REQUIRED field that fundamentally determines mapping behavior:\n\n**Simple Types (direct value mapping)**\n- `string`: Text values, converts other types to string representation\n- `number`: Numeric values, attempts conversion from strings\n- `boolean`: True/false values, converts truthy/falsy values\n\nDates are represented as strings — use `string` for date fields and\ndrive the parsing/formatting through the `extractDateFormat` /\n`generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`\nfields. There is no separate `date` enum value.\n\n**Complex Types (require additional configuration)**\n- `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array\n\n**Array Types**\n- `stringarray`: Array of strings\n- `numberarray`: Array of numbers\n- `booleanarray`: Array of booleans\n- `objectarray`: Array of objects (most common array type)\n- `arrayarray`: Array of arrays (for matrix/table structures)\n\nArray dataTypes can be populated two ways: pass a source array through\nunchanged via `extract` alone (when the source is already an array of\nthe right shape), or construct/iterate via `buildArrayHelper`.\n\nIMPORTANT: The dataType controls which additional fields are relevant:\n- For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant\n- For object types: 'mappings' array becomes relevant\n- For array types: `buildArrayHelper` is one option (see above)\n\nWhen analyzing existing mappings or generating new ones, always check dataType first\nto understand what additional fields should be present.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"extract":{"type":"string","description":"**Purpose**\nDefines how to retrieve data from the input record to populate the output field.\n\n**Guidance**\nThis field supports THREE DISTINCT PATTERNS that are easily distinguished:\n\n**1. json Path Syntax**\n- MUST start with '$' — the record root. An object record is addressed as\n  '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'\n- Used for precisely targeting data in structured JSON objects\n- Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',\n  '$[*].Tax' (every row of a grouped record)\n- Wildcards like [*] extract multiple values/objects\n\n```json\n\"extract\": \"$.customer.addresses[*]\"  // Extracts all addresses\n```\n\n**2. Handlebars Template Syntax**\n- Contains '{{' and '}}' pattern\n- Evaluated by the AFE 2.0 handlebars template engine\n- Can include logic, formatting, and computation\n- Access input record fields with {{record.fieldName}} notation; a grouped\n  (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}\n- Examples: \"{{record.firstName}} {{record.lastName}}\", \"{{#if record.isActive}}Active{{else}}Inactive{{/if}}\"\n- Valid on `object`, `objectarray`, and primitive-array dataTypes as\n  well as scalars — the rendered template output must parse into the\n  declared shape\n\n```json\n\"extract\": \"{{record.price}} {{record.currency}}\"  // Combines two fields\n```\n\n**3. Hard-Coded Value (literal string)**\n- Does NOT start with '$'\n- Does NOT contain handlebars '{{' syntax\n- System treats it as a literal string value\n- VERY COMMON for setting static/constant values\n- Examples: \"Active\", \"USD\", \"Completed\", \"true\"\n\n```json\n\"extract\": \"primary\"  // Sets field value to the literal string \"primary\"\n\"extract\": \"true\"     // Sets field value to the literal string \"true\"\n\"extract\": \"N/A\"      // Sets field value to the literal string \"N/A\"\n```\n\nThis third pattern is the simplest and most efficient way to set hard-coded values in your mappings.\nAI agents should use this pattern whenever a field needs a static value that doesn't come from\nthe input record or require computation.\n\n**Important implementation details**\n\n- JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record\n- The system maintains this context even in deeply nested mappings\n- For object mappings without child mappings, extract should return a complete object\n- When both extract and mappings are defined for objects, extract is applied first\n- The root is the record as it arrives: an object record roots at `$.field`; a\n  grouped record (an array of rows — grouped exports, file key columns, NetSuite\n  grouped saved searches) roots at the array, so its rows are addressed as\n  `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the\n  record's shape resolves to nothing without an error.\n\nFor most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.\nFor hard-coded values, simply use the literal string as the extract value.\n"},"extractDateFormat":{"type":"string","description":"Specifies the format pattern of the input date string to ensure proper parsing.\n\nUsed on string-typed mappings whose `extract` yields a date. Uses\nMoment.js-compatible formatting tokens to describe how the incoming date\nstring is structured.\n"},"extractDateTimezone":{"type":"string","description":"Specifies the timezone of the input date string using Olson/IANA timezone identifiers.\n\nUsed on string-typed mappings whose `extract` yields a date; tells the system\nhow to interpret timestamp values from the input system.\n"},"generateDateFormat":{"type":"string","description":"Specifies the output format pattern when generating a date string or converting\nfrom a Date type to String type.\n\nUses Moment.js-compatible formatting tokens to define the structure of the resulting\ndate string.\n"},"generateDateTimezone":{"type":"string","description":"Specifies the timezone to apply when generating or converting timestamp values\nusing Olson/IANA timezone identifiers.\n\nControls timezone conversion when producing date output.\n"},"default":{"type":["string","null"],"description":"Specifies a fallback value to use when extract returns empty/null or when conditional\nlogic fails and no other mapping supplies a value.\n\nExplicit JSON `null` is itself a valid fallback: the destination field is written as\nJSON null when the extract yields nothing (the Mapper UI's \"Use null as default value\"\naction). Omitting the key entirely means no fallback — the field is left out of the\noutput when the extract is empty (the UI's \"Do nothing\" action).\n"},"lookupName":{"type":"string","description":"**Purpose**\nReferences a lookup table for transforming values during the mapping process.\n\n**Usage**\n\nThe lookupName refers to a named lookup defined in the lookups array of the same resource.\n\n```json\n{\n  \"generate\": \"countryName\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.countryCode\",\n  \"lookupName\": \"countryCodeToName\"\n}\n```\n\nDuring processing, the system:\n1. Extracts the value from the input record (e.g., \"US\")\n2. Finds the lookup table with the specified name\n3. Uses the extracted value as a key in the lookup\n4. Returns the corresponding value (e.g., \"United States\")\n\n**Benefits**\n\n- **Standardization**: Ensures consistent value translation across mappings\n- **Centralization**: Define translations once and reference them in multiple places\n- **Maintainability**: Update all mappings by changing the lookup definition\n- **Readability**: Makes mappings more descriptive and self-documenting\n\nThe specific lookup capabilities depend on the context where mappings are used.\n"},"description":{"type":"string","description":"Optional free-text annotation that appears in the Mapper sidebar to provide context about\nthe mapping's purpose for collaboration and documentation.\n\nHas no functional impact on the mapping behavior.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the value produced by `extract`, before any\nconversion to `dataType`. Same enum as `dataType`. Set on leaf mappings\nonly — parent mappings (with child `mappings` or `buildArrayHelper`)\nhave no extracted value of their own; the children carry their own\n`sourceDataType`.\n\nFor date fields use `string` (JSON represents dates as strings); the\nparsing/formatting lives in `extractDateFormat` / `generateDateFormat` /\n`extractDateTimezone` / `generateDateTimezone`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"mappings":{"type":"array","description":"**Purpose**\nEnables recursive definition of nested object structures through child mapping objects.\n\n**Guidance**\nThis is the KEY FIELD that implements the recursive pattern at the core of this schema:\n\n**When to Use**\n- REQUIRED when dataType = \"object\" (unless you are copying an entire object from the input record)\n- REQUIRED in buildArrayHelper.mappings when defining complex object array elements\n- NEVER used with simple types (string, number, boolean, date)\n\n**Behavior**\n- Each mapping in this array becomes a property of the parent object\n- The full Mappings schema is repeated recursively at each level\n- Can be nested to any depth for complex hierarchical structures\n\n**Context Handling**\n- Each level of nesting changes the mapping CONTEXT for 'generate'\n- The extraction CONTEXT always remains the original input record\n- This means child mappings can pull data from anywhere in the input record\n\n**Common Patterns**\n\n**Nested Objects**\n```json\n{\n  \"generate\": \"customer\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\n      \"generate\": \"contact\",\n      \"dataType\": \"object\",\n      \"mappings\": [\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.customerEmail\"}\n      ]\n    }\n  ]\n}\n```\n\n**Multiple Fields in Object**\n```json\n{\n  \"generate\": \"address\",\n  \"dataType\": \"object\",\n  \"mappings\": [\n    {\"generate\": \"street\", \"dataType\": \"string\", \"extract\": \"$.address.line1\"},\n    {\"generate\": \"city\", \"dataType\": \"string\", \"extract\": \"$.address.city\"},\n    {\"generate\": \"country\", \"dataType\": \"string\", \"extract\": \"$.address.country\"}\n  ]\n}\n```\n\nIMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = \"object\"\nor if you're inside buildArrayHelper.mappings for objectarray elements. These are the only\nvalid contexts for the mappings array.\n","items":{"$ref":"#/components/schemas/items"}},"buildArrayHelper":{"type":"array","description":"**Purpose**\nConfigures how to construct arrays in the output record, handling various array types and inputs.\n\n**Guidance**\nThis is the REQUIRED mechanism for ALL array data types:\n\n**When to Use**\n- REQUIRED when dataType ends with \"array\" (stringarray, objectarray, etc.)\n- Each entry in this array contributes elements to the output array\n- Multiple entries allow combining data from different input arrays\n\n**Array Type Handling**\n\n**For Simple Arrays (stringarray, numberarray, booleanarray)**\n- Only the 'extract' field is used to pull values\n- JSON path with wildcards (e.g., $.items[*].name) returns multiple values;\n  on a grouped (array) record the record itself is the array, so the\n  path roots at it ($[*].name — one value per row)\n- Each result is converted to the appropriate primitive type\n```json\n{\n  \"generate\": \"productNames\",\n  \"dataType\": \"stringarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.products[*].name\"}\n  ]\n}\n```\n\n**For Object Arrays (objectarray) - three patterns**\n\n1. Extract Only (existing objects):\n```json\n{\n  \"generate\": \"contacts\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\"extract\": \"$.account.primaryContacts[*]\"},  // Pull primary contact objects\n    {\"extract\": \"$.account.secondaryContacts[*]\"},  // Pull secondary contact objects\n    {\"extract\": \"$.vendor.contactPersons[*]\"},  // Pull vendor contact objects\n    {\"extract\": \"$.subsidiaries[*].mainContact\"}  // Pull main contact from each subsidiary\n  ]\n}\n```\n\n2. Mappings Only (constructed object):\n```json\n{\n  \"generate\": \"contactInfo\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"mappings\": [  // Creates one object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"primary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.primaryEmail\"}\n      ]\n    },\n    {\n      \"mappings\": [  // Creates another object in the array\n        {\"generate\": \"type\", \"dataType\": \"string\", \"extract\": \"secondary\"},\n        {\"generate\": \"email\", \"dataType\": \"string\", \"extract\": \"$.secondaryEmail\"}\n      ]\n    }\n  ]\n}\n```\nEach constructed entry contributes exactly one element, in entry\norder; writing the entry with `\"extract\": \"$\"` is equivalent to\nomitting the extract (both anchor the element at the record root).\nA fixed number of static elements is built from that many sibling\nconstructed entries.\n\n3. Extract AND Mappings (transform input arrays):\n```json\n{\n  \"generate\": \"lineItems\",\n  \"dataType\": \"objectarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.order.items[*]\",  // For each item in the array\n      \"mappings\": [  // Transform to this structure using the composite object\n        {\"generate\": \"sku\", \"dataType\": \"string\", \"extract\": \"$.order.items.productId\"},  // Notice: items is singular\n        {\"generate\": \"quantity\", \"dataType\": \"number\", \"extract\": \"$.order.items.qty\"},   // Notice: items is singular\n        {\"generate\": \"orderNumber\", \"dataType\": \"string\", \"extract\": \"$.order.id\"},       // Access parent data\n        {\"generate\": \"customerName\", \"dataType\": \"string\", \"extract\": \"$.customerName\"}   // Access root data\n      ]\n    }\n  ]\n}\n```\n\n**For Arrays of Arrays (arrayarray)**\n- Similar to objectarray, but inner arrays have empty 'generate' fields\n- Used for matrix/table structures\n```json\n{\n  \"generate\": \"matrix\",\n  \"dataType\": \"arrayarray\",\n  \"buildArrayHelper\": [\n    {\n      \"extract\": \"$.rows[*]\",  // For each row in the rows array\n      \"mappings\": [\n        {\n          \"dataType\": \"numberarray\",  // Note: No generate field for inner arrays\n          \"buildArrayHelper\": [\n            {\"extract\": \"$.rows.columns[*]\"}  // Notice: \"rows\" is singular in the composite object\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n**Important details**\n\n- When both extract and mappings are provided, the system creates special composite objects\n  that maintain hierarchical context during processing\n- This enables accessing both the current array element AND its parent context\n- An ITERATING entry's extract MUST be a JSON path that iterates an array:\n  '$.items[*]' when the array is a field of an object record, or '$[*]'\n  (objectarray) / '$[*].field' (primitive arrays) when the record itself is a\n  grouped array of rows. A CONSTRUCTED entry (child mappings building one\n  element) instead omits extract or sets it to exactly \"$\" — never rewrite \"$\"\n  into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the\n  entire destination array as null without raising a validation error\n- Each array helper entry acts independently, potentially adding multiple elements\n\nThe buildArrayHelper is the most complex part of the mappings system - always analyze the\ndataType first to understand which pattern is appropriate.\n","items":{"type":"object","properties":{"extract":{"type":"string","description":"JSON path expression that identifies the input array or values to extract.\n\nFor objectarray with mappings, this defines which input objects to iterate through.\nThe JSON path must return either a single object or an array of objects.\n\nFor a CONSTRUCTED entry (child mappings building exactly one element from\nrecord-root fields and constants), omit this field or set it to exactly \"$\" —\nthe two spellings are equivalent. Indexed or comma-joined forms ('$[0]',\n'$[0],$[0]') are not valid at the entry level: the processor renders the\nentire destination array as null without raising a validation error.\n\nThe system creates special composite objects during processing to maintain\nhierarchical relationships, allowing easy access to both the current array item\nand its parent contexts.\n"},"sourceDataType":{"type":"string","description":"Declares the JSON type of the input array being iterated, to ensure\nproper type handling during array construction. Same enum as `dataType`.\n","enum":["string","number","boolean","object","stringarray","numberarray","booleanarray","objectarray","arrayarray"]},"default":{"type":["string","null"],"description":"Specifies a fallback value when the extracted array element is empty or\nnot found in the input data.\n\nExplicit JSON `null` is itself a valid fallback (the element is written as\nJSON null); omitting the key means no fallback is applied.\n"},"conditional":{"type":"object","description":"Defines conditional rules for including each array element in the result.\n","properties":{"when":{"type":"string","description":"Specifies the condition that must be met for an array element to be included.\n\n'extract_not_empty' only includes elements where the extract field returns a value.\n","enum":["extract_not_empty"]}}},"mappings":{"type":"array","description":"Contains recursive mapping definitions for complex array element transformations.\n\n**Composite object mechanism**\n\nWhen both 'extract' and 'mappings' are used together, the system implements a sophisticated\n\"composite object\" approach that is crucial for AI agents to understand:\n\n1. The system starts with the complete input record\n\n2. For each array element matched by the extract path, it creates a modified version of\n   the input record where:\n   - Array paths in the extract JSON path are REPLACED with single objects\n   - Each array ([]) in the path is converted to a single object ({})\n   - This preserves the hierarchical relationship between nested arrays\n\n**Example**\n\nGiven an input record:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": [\n      {\n        \"id\": \"O-001\",\n        \"items\": [\n          {\"sku\": \"ABC\", \"qty\": 2},\n          {\"sku\": \"XYZ\", \"qty\": 1}\n        ]\n      },\n      {\n        \"id\": \"O-002\",\n        \"items\": [\n          {\"sku\": \"DEF\", \"qty\": 3}\n        ]\n      }\n    ]\n  }\n}\n```\n\nWith extract path: `$.customer.orders[*].items[*]`\n\nFor each item, the system creates a composite object like:\n```json\n{\n  \"customer\": {\n    \"name\": \"John Doe\",\n    \"orders\": {  // Note: Array replaced with single object\n      \"id\": \"O-001\",\n      \"items\": {  // Note: Array replaced with single object\n        \"sku\": \"ABC\",\n        \"qty\": 2\n      }\n    }\n  }\n}\n```\n\nThen in your mappings, you can access:\n- The current item: `$.customer.orders.items.sku`\n- The parent order: `$.customer.orders.id`\n- Top-level data: `$.customer.name`\n\nThis approach allows for precise mapping from deeply nested structures while maintaining\naccess to all contextual parent data, without requiring complex array index management.\n\n**Implementation guidance**\n\nWhen implementing the composite object mechanism:\n\n1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)\n2. For each array in the path, understand that it will be replaced with a single object\n3. In the mappings, use paths that reference these arrays as if they were objects\n4. Remember that every mapping still has access to the full input record context\n5. This mechanism is especially powerful when mapping hierarchical data like:\n   - Order → Line Items → Taxes/Discounts\n   - Customer → Addresses → Address Lines\n   - Invoice → Line Items → Serial Numbers\n\nThe extract path effectively tells the system \"iterate through these arrays\",\nwhile the composite object mechanism ensures you can still access both the\ncurrent array item AND its parent context during mapping.\n","items":{"$ref":"#/components/schemas/items"}}}}},"status":{"type":"string","description":"**Purpose**\nRequired on every mapping entry. Controls whether the mapping is applied.\n\n**Guidance**\nEmit `\"Active\"` for mappings that should run; `\"Draft\"` saves an\nin-progress mapping without the Active-only field validations. The\nAPI rejects a mapping missing this field\n(validation error: \"Mapping object must have status field present.\").\n","enum":["Active","Draft"]},"conditional":{"type":"object","description":"**Purpose**\nDefines conditional processing rules for the entire mapping.\n\n**Guidance**\nThese conditions determine whether the mapping is applied based on record\nstate or field content:\n\n**When to Use**\n- When a mapping should only be applied in specific circumstances\n- To implement conditional logic without using complex handlebars expressions\n- For creating mappings that only run during create or update operations\n\n**Available Conditions**\n\n- `record_created`: Apply only when creating a new record\n  Useful for setting initial values that should not be overwritten during updates\n\n- `record_updated`: Apply only when updating an existing record\n  Useful for transformation logic that should only run during updates\n\n- `extract_not_empty`: Apply only when the extract field returns a value\n  Useful for conditional mapping based on input data availability\n\n**Example**\n```json\n{\n  \"generate\": \"statusMessage\",\n  \"dataType\": \"string\",\n  \"status\": \"Active\",\n  \"extract\": \"$.status.message\",\n  \"conditional\": {\n    \"when\": \"extract_not_empty\"  // Only map when status.message exists\n  }\n}\n```\n","properties":{"when":{"type":"string","description":"Specifies the condition that triggers application of this mapping:\n- record_created: Apply only when creating a new record\n- record_updated: Apply only when updating an existing record\n- extract_not_empty: Apply only when the extract field returns a value\n","enum":["record_created","record_updated","extract_not_empty"]}}}},"required":["dataType"]},"Transform":{"type":"object","description":"Configuration for transforming data during processing operations. This object enables\nreshaping of records.\n\n**Transformation capabilities**\n\nCeligo's transformation engine offers powerful features for data manipulation:\n- Precise field mapping with JSONPath expressions\n- Support for any level of nested arrays\n- Formula-based field value generation\n- Dynamic references to flow and integration settings\n\n**Implementation approaches**\n\nThere are two distinct transformation mechanisms available:\n\n**Rule-Based Transformation (`type: \"expression\"`)**\n- **Best For**: Most transformation scenarios from simple to complex\n- **Capabilities**: Field mapping, formula calculations, lookups, nested data handling\n- **Advantages**: Visual configuration, no coding required, intuitive interface\n- **Configuration**: Define rules in the `expression` object\n- **Use When**: You have clear mapping requirements or need to reshape data structure\n\n**Script-Based Transformation (`type: \"script\"`)**\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Capabilities**: Full programmatic control, custom processing, complex business rules\n- **Advantages**: Maximum flexibility, can implement any transformation logic\n- **Configuration**: Reference a script in the `script` object\n- **Use When**: Visual transformation tools aren't sufficient for your use case\n","properties":{"type":{"type":"string","description":"Determines which transformation mechanism to use. This choice affects which properties\nmust be configured and how transformation logic is implemented.\n\n**Available types**\n\n**Rule-Based Transformation (`\"expression\"`)**\n- **Required Config**: The `expression` object with mapping definitions\n- **Behavior**: Applies declarative rules to reshape data\n- **Best For**: Most transformation scenarios from simple to complex\n- **Advantages**: Visual configuration, no coding required\n\n**Script-Based Transformation (`\"script\"`)**\n- **Required Config**: The `script` object with _scriptId and function\n- **Behavior**: Executes custom JavaScript to transform data\n- **Best For**: Extremely complex logic or proprietary algorithms\n- **Advantages**: Maximum flexibility, can implement any logic\n\n**Implementation guidance**\n\n1. For standard data transformations, use `\"expression\"`\n2. For complex logic or specialized processing, use `\"script\"`\n3. When selecting a type, you must configure the corresponding object:\n    - `type: \"expression\"` requires the `expression` object\n    - `type: \"script\"` requires the `script` object\n","enum":["expression","script"]},"expression":{"type":"object","description":"Configuration for declarative rule-based transformations. This object enables reshaping data\nwithout requiring custom code.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"expression\" and should not be\nconfigured otherwise. It provides a standardized way to define transformation rules that\ncan map, modify, and generate data elements.\n\n**Implementation guidance**\n\nThe expression system uses a rule-based approach where:\n- Field mappings define how input data is transformed to target fields\n- Formulas can be used to calculate or generate new values\n- Lookups can enrich data by fetching related information\n- Mode determines how records are processed (create new or modify existing)\n","properties":{"version":{"type":"string","description":"Version of the expression format. Determines which rules\nproperty contains the transformation logic.\n","enum":["1","2"]},"rules":{"type":"array","description":"Transformation rules for version 1 expressions. An array of\nrule groups; each group is an array of field-mapping objects.\nMost transforms have a single group. Present when `version`\nis `\"1\"`. The output record contains ONLY the generated\nfields — every unmapped field is dropped (v1 has no\nequivalent of Transform 2.0's `modify` mode), and the\nrecord's trace key does not survive the rebuild.\n","items":{"type":"array","items":{"type":"object","properties":{"extract":{"type":"string","description":"Source field path to read from. Supports multiple\nsyntaxes: bare field names (`id`), dot notation\n(`fulfillment.shipment_id`), slash-prefixed paths\nfor XML (`/FeedProcessingStatus`), wildcards (`*.id`,\n`*.[Internal ID]`), and array indexing (`SDF[0]`).\n"},"generate":{"type":"string","description":"Target field name to write to. Typically a bare name\n(`id`) or dot path (`SDF.Filter.ID`).\n"},"key":{"type":"string","description":"Auto-generated identifier for this rule, used by the\nUI to track individual rules for editing and reordering.\n"}},"required":["extract","generate"]}}},"rulesTwoDotZero":{"type":"object","description":"Configuration for version 2 transformation rules. This object contains the core logic\nfor how data is mapped, enriched, and transformed.\n\n**Capabilities**\n\nTransformation 2.0 provides:\n- Precise field mapping with JSONPath expressions\n- Support for deeply nested data structures\n- Formula-based field generation\n- Dynamic lookups for data enrichment\n- Multiple operating modes to fit different scenarios\n","properties":{"mode":{"type":"string","description":"Transformation mode that determines how records are handled during processing.\n\n**Available modes**\n\n**Create Mode (`\"create\"`)**\n- **Behavior**: Builds entirely new output records from inputs\n- **Use When**: Output structure differs significantly from input\n- **Advantage**: Clean slate approach, no field inheritance\n\n**Modify Mode (`\"modify\"`)**\n- **Behavior**: Makes targeted edits to existing records\n- **Use When**: Output structure should remain similar to input\n- **Advantage**: Preserves unmapped fields from the original record\n","enum":["create","modify"]},"mappings":{"$ref":"#/components/schemas/Mappings"},"lookups":{"allOf":[{"description":"Shared lookup tables used across all mappings defined in the transformation rules.\n\n**Purpose**\n\nLookups provide centralized value translation that can be referenced from any mapping\nin your transformation configuration. They enable consistent translation of codes, IDs,\nand values between systems without duplicating translation logic.\n\n**Usage in transformations**\n\nLookups are particularly valuable in transformations for:\n\n- **Data Normalization**: Standardizing values from diverse source systems\n- **Code Translation**: Converting between different coding systems (e.g., status codes)\n- **Field Enrichment**: Adding descriptive values based on ID or code lookups\n- **Cross-Reference Resolution**: Mapping identifiers between integrated systems\n\n**Implementation**\n\nLookups are defined once in this array and referenced by name in mappings:\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"statusMapping\",\n    \"map\": {\n      \"A\": \"Active\",\n      \"I\": \"Inactive\",\n      \"P\": \"Pending\"\n    },\n    \"default\": \"Unknown Status\"\n  }\n]\n```\n\nThen referenced in mappings using the lookupName property:\n\n```json\n{\n  \"generate\": \"status\",\n  \"dataType\": \"string\",\n  \"extract\": \"$.statusCode\",\n  \"lookupName\": \"statusMapping\"\n}\n```\n\nThe system automatically applies the lookup during transformation processing.\n\nFor complete details on lookup properties and behavior, see the Lookups schema.\n"},{"$ref":"#/components/schemas/Lookups"}]},"inputContext":{"type":"string","enum":["record","envelope"],"description":"Controls the JSON shape the transformTwoDotZero processor\nevaluates `mappings[].extract` JSONPath values against at\nflow runtime. Applies only to Transform 2.0 (v2,\n`rulesTwoDotZero`); v1 transforms (the `rules` array on\n`transform.expression.rules`) and script-mode transforms\nignore this field.\n"}}}}},"script":{"type":"object","description":"Configuration for programmable script-based transformations. This object enables complex, custom\ntransformation logic beyond what expression-based transformations can provide.\n\n**Usage context**\n\nThis object is REQUIRED when `transform.type` is set to \"script\" and should not be configured\notherwise. It provides a way to execute custom JavaScript code to transform data according to\nspecialized business rules or complex algorithms.\n\n**Implementation approach**\n\nScript-based transformation works by:\n1. Executing the specified function from the referenced script\n2. Passing input data to the function\n3. Using the function's return value as the transformed output\n\n**Common use cases**\n\nScript transformation is ideal for:\n- Complex business logic that can't be expressed through mappings\n- Algorithmic transformations requiring computation\n- Dynamic transformations based on external factors\n- Legacy system data format compatibility\n- Multi-stage processing with intermediate steps\n\nOnly use script-based transformation when expression-based transformation is insufficient.\nScript transformation requires maintaining custom code, which adds complexity to the integration.\n","properties":{"_scriptId":{"type":"string","description":"Reference to a predefined script resource containing the transformation logic.\n\nThe referenced script should contain the function specified in the\n'function' property.\n","format":"objectid"},"function":{"type":"string","description":"Name of the function within the script to execute for transformation. This function\nmust exist in the script referenced by _scriptId.\n"}}}}},"Lookups":{"type":"array","description":"Configuration for value-to-value transformations using lookup tables.\n\n**Purpose**\n\nLookups provide a way to translate values from one system to another. They transform\ninput values into output values using either static mapping tables or\ndynamic lookup caches.\n\n**Lookup mechanisms**\n\nThere are two distinct lookup mechanisms available:\n\n1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource\n   - Best for: Small, fixed sets of values that rarely change\n   - Implementation: Configure the `map` object with input-to-output value mappings\n   - Example: Country codes, status values, simple translations\n\n2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account\n   - Best for: Large datasets, frequently changing values, or complex reference data\n   - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently\n   - Example: Product catalogs, customer databases, pricing information\n\n**Property usage**\n\nThere are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:\n\n1. **For Static Mappings**: Configure the `map` property with a direct key-value object\n   ```json\n   \"map\": {\"US\": \"United States\", \"CA\": \"Canada\"}\n   ```\n\n2. **For Dynamic Lookups**: Configure the following properties:\n   - `_lookupCacheId`: Reference to the lookup cache resource\n   - `extract`: JSON path to extract specific value from the returned lookup object\n\n**When to use**\n\nLookups are ideal for:\n\n1. **Value Translation**: Mapping codes or IDs to human-readable values\n\n2. **Data Enrichment**: Adding related information to records during processing\n\n3. **Normalization**: Ensuring consistent formatting of values across systems\n\n**Implementation details**\n\nLookups can be referenced in:\n\n1. **Field Mappings**: Direct use in field transformation configurations\n\n2. **Handlebars Templates**: Use within templates with the syntax:\n   ```\n   {{lookup 'lookupName' record.fieldName}}\n   ```\n\n**Example usage**\n\n```json\n\"lookups\": [\n  {\n    \"name\": \"countryCodeToName\",\n    \"map\": {\n      \"US\": \"United States\",\n      \"CA\": \"Canada\",\n      \"UK\": \"United Kingdom\"\n    },\n    \"default\": \"Unknown Country\",\n    \"allowFailures\": true\n  },\n  {\n    \"name\": \"productDetails\",\n    \"_lookupCacheId\": \"60a2c4e6f321d800129a1a3c\",\n    \"extract\": \"$.details.price\",\n    \"allowFailures\": false\n  }\n]\n```\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for the lookup table within this configuration.\n\nThis name must be unique within the scope where the lookup is defined and is used to reference\nthe lookup in handlebars templates with the syntax {{lookup 'name' value}}.\n\nChoose descriptive names that indicate the transformation purpose, such as:\n- \"countryCodeToName\" for country code to full name conversion\n- \"statusMapping\" for status code translations\n- \"departmentCodes\" for department code to name mapping\n"},"map":{"type":["object","null"],"description":"The lookup mapping table as key-value pairs. The platform stores `null`\nhere on dynamic lookups, which resolve values at runtime instead of\nfrom a static table.\n\nThis object contains the input values as keys and their corresponding\noutput values. When a input value matches a key in this object,\nit will be replaced with the corresponding value.\n\nThe map should be kept to a reasonable size (typically under 100 entries)\nfor optimal performance. For larger mapping requirements, consider using\ndynamic lookups instead.\n\nMaps can include:\n- Simple code to name conversions: {\"US\": \"United States\"}\n- Status transformations: {\"A\": \"Active\", \"I\": \"Inactive\"}\n- ID to name mappings: {\"100\": \"Marketing\", \"200\": \"Sales\"}\n\nValues can be strings, numbers, or booleans, but all are stored as strings\nin the configuration.\n"},"_lookupCacheId":{"type":"string","description":"Reference to a LookupCache resource that contains the reference data for the lookup.\n\n**Purpose**\n\nThis field connects the lookup to an external data source that has been cached in the system.\nUnlike static lookups that use the `map` property, dynamic lookups can reference large datasets\nor frequently changing information without requiring constant updates to the integration.\n\n**Implementation details**\n\nThe LookupCache resource referenced by this ID contains:\n- The data records to be used as a reference source\n- Configuration for how the data should be indexed and accessed\n- Caching parameters to balance performance with data freshness\n\n**Usage patterns**\n\nCommonly used to reference:\n- Product catalogs or SKU databases\n- Customer or account information\n- Pricing tables or discount rules\n- Complex business logic lookup tables\n\nFormat: 24-character hexadecimal string (MongoDB ObjectId)\n","format":"objectid"},"extract":{"type":"string","description":"JSON path expression that extracts a specific value from the cached lookup object.\n\n**Purpose**\n\nWhen using dynamic lookups with a LookupCache, this JSON path identifies which field to extract\nfrom the cached object after it has been retrieved using the lookup key.\n\n**Implementation details**\n\n- Must use JSON path syntax (similar to mapping extract fields)\n- Operates on the cached object returned by the lookup operation\n- Examples:\n  - \"$.name\" - Extract the name field from the top level\n  - \"$.details.price\" - Extract a nested price field\n  - \"$.attributes[0].value\" - Extract a value from the first element of an array\n\n**Usage scenario**\n\nWhen a lookup cache contains complex objects:\n```json\n// Cache entry for key \"PROD-123\":\n{\n  \"id\": \"PROD-123\",\n  \"name\": \"Premium Widget\",\n  \"details\": {\n    \"price\": 99.99,\n    \"currency\": \"USD\",\n    \"inStock\": true\n  }\n}\n```\n\nSetting extract to \"$.details.price\" would return 99.99 as the lookup result.\n\nIf no extract is provided, the entire cached object is returned as the lookup result.\n"},"default":{"type":["string","null"],"description":"Default value to use when the source value is not found in the lookup map.\nThe platform stores `null` here when no default is configured.\n\nThis value is used as a fallback when:\n1. The source value doesn't match any key in the map\n2. allowFailures is set to true\n\nSetting an appropriate default helps prevent flow failures due to unexpected\nvalues and provides predictable behavior for edge cases.\n\nCommon default patterns include:\n- Descriptive unknowns: \"Unknown Country\", \"Unspecified Status\"\n- Original value indicators: \"{Original Value}\", \"No mapping found\"\n- Neutral values: \"Other\", \"N/A\", \"Miscellaneous\"\n\nIf allowFailures is false and no default is specified, the flow will fail\nwhen encountering unmapped values.\n"},"allowFailures":{"type":["boolean","null"],"description":"When true, missing lookup values will use the default value rather than causing an error.\n\n**Behavior control**\n\nThis field determines how the system handles source values that don't exist in the map:\n\n- true: Use the default value for missing mappings and continue processing\n- false: Treat missing mappings as errors, failing the record\n\n**Recommendation**\n\nSet this to true when:\n- New source values might appear over time\n- Data quality issues could introduce unexpected values\n- Processing should continue even with imperfect mapping\n\nSet this to false when:\n- Complete data accuracy is critical\n- All possible source values are known and controlled\n- Missing mappings indicate serious data problems that should be addressed\n\nThe best practice is typically to set allowFailures to true with a meaningful\ndefault value, so flows remain operational while alerting you to missing mappings.\n"}}}},"Form":{"type":"object","description":"Configuration for creating user-friendly settings forms that make it easier for less technical users\nto configure integration resources.\n\n**Settings form builder**\n\nThe Settings Form Builder allows you to create or edit user-friendly fields that prompt for text entry\nor selections that will be returned as settings applied to this resource. Your forms can include any\nfield types that you see elsewhere in integrator.io, such as:\n\n- Text fields\n- Dropdown selections\n- Checkboxes\n- Radio buttons\n- Date pickers\n- Multi-select fields\n- Search fields\n\nForm fields make it much easier for less technical users to work with your integration settings by:\n\n- Providing clear labels and help text\n- Enforcing validation rules\n- Offering pre-defined selection options\n- Grouping related settings logically\n- Supporting conditional visibility\n- Creating a consistent user experience\n","properties":{"form":{"type":"object","description":"Configuration that defines the structure, fields, and behavior of the settings form.\n\nThis object contains the complete definition of the form's layout, fields, validation rules,\nand interactive behaviors. The specific structure depends on the form complexity and can include\nfield definitions, sections, conditional display logic, and default values.\n\nThe form configuration is typically created and managed through the visual Form Builder interface\nrather than edited directly as JSON.\n","properties":{"fieldMap":{"type":"object","description":"A mapping of field identifiers to their configuration objects.\nEach key in this object represents a unique field ID, and the value contains\nall the configuration settings for that specific form field.\n","additionalProperties":{"type":"object","description":"Configuration for an individual form field.\n","properties":{"id":{"type":"string","description":"Unique identifier for this field within the form.\nThis value typically matches the key in the fieldMap object.\n"},"name":{"type":"string","description":"Name of the field, used as the property name when generating the settings object\nfrom the submitted form data.\n"},"type":{"type":"string","description":"The type of form control to render for this field.\n","enum":["text","checkbox","radiogroup","relativeuri","editor","keyvalue","select","multiselect","toggle","datetime","date","exportSelect","staticMap"]},"label":{"type":"string","description":"Display label shown next to the field in the form.\n"},"description":{"type":"string","description":"Detailed explanation text that appears below the field, providing more context\nthan the label or helpText.\n"},"helpText":{"type":"string","description":"Explanatory text that appears when hovering over the help icon next to the field.\nUsed to provide additional guidance on how to use the field.\n"},"required":{"type":"boolean","description":"When true, the field must have a value before the form can be submitted.\n","default":false},"multiline":{"type":"boolean","description":"For text fields, determines whether the input should be a multi-line text area\ninstead of a single-line input.\n","default":false},"rowsMax":{"type":"integer","description":"For multiline text fields, specifies the maximum number of visible rows.\n"},"inputType":{"type":"string","description":"For text fields, specifies the HTML input type attribute to apply additional\nvalidation or specialized input behavior.\n","enum":["text","number","email","password","tel","url"]},"delimiter":{"type":"string","description":"For text fields, specifies a character to use for splitting the input into an array.\nUsed for collecting multiple values in a single text field.\n"},"mode":{"type":"string","description":"For editor fields, specifies the type of content being edited for syntax highlighting.\n","enum":["json","xml","csv","text"]},"keyName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the key input.\n"},"valueName":{"type":"string","description":"For keyvalue fields, specifies the placeholder and field name for the value input.\n"},"showDelete":{"type":"boolean","description":"For keyvalue fields, determines whether to show a delete button for each key-value pair.\n"},"doNotAllowFutureDates":{"type":"boolean","description":"For date and datetime fields, restricts selection to dates not in the future.\n"},"skipTimezoneConversion":{"type":"boolean","description":"For datetime fields, prevents automatic timezone conversion of the date value.\n"},"options":{"type":"array","description":"For fields that present choices (select, multiselect, radiogroup, toggle), defines\nthe available options.\n","items":{"anyOf":[{"title":"Option group","type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"oneOf":[{"title":"String value","type":"string"},{"title":"Label-value pair","type":"object","properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]},"description":"Array of option values/labels to display in the selection control.\n"}}},{"title":"Label-value pair","type":"object","required":["label"],"properties":{"label":{"type":"string","description":"Display text for the option.\n"},"value":{"type":"string","description":"Value to store when this option is selected.\n"}}}]}},"visibleWhen":{"type":"array","description":"Conditional display rules that determine when this field should be visible.\nIf empty or not provided, the field is always visible.\n","items":{"type":"object","properties":{"field":{"type":"string","description":"The ID of another field whose value controls the visibility of this field.\n"},"is":{"type":"array","items":{"type":["string","boolean","number","null"]},"description":"Array of values - if the referenced field has any of these values,\nthis field will be visible. Values may be strings, booleans (for\ncheckbox/toggle fields), numbers (for numeric inputs), or null.\n"}}}}}}},"layout":{"type":"object","description":"Defines how the form fields are arranged and grouped in the UI.\nThe layout can organize fields into columns, sections, or other visual groupings.\n","properties":{"type":{"type":"string","description":"The type of layout to use for the form.\n","enum":["column","collapse","box","indent","tabWithoutSave","verticalTabWithoutSave"]},"containers":{"type":"array","description":"Array of container objects that group fields or contain nested containers.\nEach container can represent a column, box, indented section, or collapsible section.\n","items":{"type":"object","properties":{"type":{"type":"string","description":"The visual style of the container.\n","enum":["indent","box","collapse"]},"label":{"type":"string","description":"The heading text displayed for this container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this container.\nEach ID must correspond to a key in the fieldMap object.\n"},"containers":{"type":"array","description":"Nested containers within this container. Allows for hierarchical organization\nof fields with different visual styles.\n","items":{"type":"object","properties":{"label":{"type":"string","description":"The heading text displayed for this nested container.\n"},"fields":{"type":"array","items":{"type":"string"},"description":"Array of field IDs that should be displayed in this nested container.\n"}}}}}}}}}},"additionalProperties":true},"init":{"type":"object","description":"Configuration for custom JavaScript initialization that executes when the form is first loaded.\n\nThis object defines a JavaScript hook that prepares the form for use, sets initial field values,\nperforms validation, or otherwise customizes the form behavior before it is displayed to the user.\n\n**Function signature**\n\nThe initialization function is invoked with a single 'options' argument containing contextual information:\n```javascript\nfunction formInit(options) {\n  // Process options and return the form object\n  return options.resource.settingsForm.form;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.resource` - The current resource being configured\n- `options.parentResource` - The parent of the current resource\n- `options.grandparentResource` - The grandparent of the current resource\n- `options.license` - For integration apps, the license provisioned to the integration\n- `options.parentLicense` - For integration apps, the parent of the license\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Dynamically generate field options based on resource configuration\n- Pre-populate default values from related resources\n- Apply conditional logic that depends on resource properties\n- Add, remove, or modify form fields based on user permissions or account settings\n- Fetch external data to populate selection options\n- Implement complex validation rules that depend on resource context\n- Create branching form experiences based on user selections\n\n**Return value**\n\nThe function must return a valid form object that the UI can render.\nThrowing an exception will signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called when the form\nis initialized and should handle any custom setup logic.\n\nThe function must follow the expected signature and return a valid form object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the initialization function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}}}},"Settings":{"type":"object","description":"Configuration settings that can be accessed by hooks, filters, mappings and handlebars templates at runtime.\n\nIt enables customization of the resource's logic, allowing hooks, mappings, filters, and\nhandlebars to access and apply the settings at runtime.\n\n**Usage**\n\nThe settings object can store arbitrary JSON data that you want to save with the resource.\nWhile it's often populated through a form defined in the `settingsForm` field, you can also:\n\n- Directly provide JSON settings without using a form\n- Store configuration values used by hooks and templates\n- Create resource-specific constants and parameters\n- Maintain lookup tables or mapping structures\n- Define conditional logic parameters\n\n**Accessibility**\n\nSettings are available in:\n- All handlebars fields for building dynamic payloads\n- Field mapping expressions\n- JavaScript hooks via the options object\n- Filters and transformations\n\nAt runtime, the settings objects in the step's execution chain are gathered into a\nsingle `settings` context keyed by fixed scope keys. Flow runs populate the full\nchain: `settings.integration.*`, `settings.flowGrouping.*` (the flow group the flow\nbelongs to), `settings.flow.*`, `settings.connection.*`, `settings.iClient.*`, and\nthe running step's own scope — `settings.export.*` on exports/lookups,\n`settings.import.*` on imports (the key matches the step type). Steps executing\ninside a My API or a Tool receive only the step's own scope plus\n`settings.connection.*` / `settings.iClient.*`; the integration, flowGrouping, and\nflow scopes resolve empty there. The scope key is literal — resource display names\nand settingsForm section labels are never part of the path. The segments after the\nscope mirror the stored settings JSON key path exactly: a top-level field is\n`settings.<scope>.<fieldId>`, and nested objects add one segment per JSON key\n(e.g. `settings.flowGrouping.Customer.region` when the group's settings JSON nests\n`region` under `Customer`). References without a scope key\n(e.g. `{{settings.myField}}`) resolve to empty strings.\n\n**Best practices**\n\nFor non-technical users, create a custom form instead of editing the JSON directly.\nThis provides a user-friendly interface for updating settings without requiring JSON knowledge.\n","additionalProperties":true},"MockOutput":{"type":["object","null"],"description":"Sample data that simulates the output from an export for testing and configuration purposes.\n\nMock output allows you to configure and test flows without executing the actual export or\nwaiting for real-time data to arrive. This is particularly useful for:\n- Initial flow configuration and testing\n- Mapping development without requiring live data\n- Generating metadata for downstream flow steps\n- Creating realistic test scenarios\n- Documenting expected data structures\n\n**Structure**\n\nThe mock output must follow the integrator.io canonical format, which consists of a\n`page_of_records` array containing record objects. Each record object has a `record`\nproperty that contains the actual data fields.\n\n```json\n{\n  \"page_of_records\": [\n    {\n      \"record\": {\n        \"field1\": \"value1\",\n        \"field2\": \"value2\",\n        ...\n      }\n    },\n    ...\n  ]\n}\n```\n\n**Usage**\n\nWhen executing a test run or configuring a flow, integrator.io will use this mock output\ninstead of executing the export to retrieve live data. This allows you to:\n- Test mappings with representative data\n- Configure downstream flow steps without waiting for real data\n- Simulate various data scenarios\n\n**Limitations**\n\n- Maximum of 10 records\n- Maximum size of 1 MB\n- Must follow the canonical format shown above\n\nMock output can be populated automatically from preview data or entered manually.\n","properties":{"page_of_records":{"type":"array","description":"Array of record objects in the integrator.io canonical format.\n\nEach item in this array represents one record that would be processed\nby the flow during execution.\n","items":{"type":"object","properties":{"record":{"type":"object","description":"Container for the actual record data fields.\n\nThe structure of this object will vary depending on the specific\nexport configuration and the source system's data structure.\n","additionalProperties":true}}}}}},"PreSave":{"type":"object","description":"Defines a JavaScript hook that executes before the resource is saved.\n\nThis hook allows for programmatic validation, transformation, or enrichment of the\nresource itself before it is persisted. It can be used to enforce business rules,\nset derived properties, or implement cross-field validations that can't be expressed\nthrough the standard UI.\n\n**Function signature**\n\nThe preSave function is invoked with a single 'options' argument containing:\n```javascript\nfunction preSave(options) {\n  // Process options and return the modified resource\n  return options.newResource;\n}\n```\n\n**Available context**\n\nThe 'options' argument provides access to:\n- `options.newResource` - The resource being saved (with pending changes)\n- `options.oldResource` - The previous version of the resource (before changes)\n- `options.sandbox` - Boolean flag indicating whether the script is running in a sandbox environment\n\n\n**Common uses**\n\n- Enforcing complex business rules across multiple fields\n- Automatically deriving field values based on other configuration\n- Performing validation that depends on external systems or data\n- Normalizing or standardizing configuration values\n- Adding computed or derived properties\n- Implementing versioning or change tracking\n- Dynamically looking up data using the Celigo API module to enrich configuration\n\n**Return value**\n\nThe function must return the newResource object (potentially modified) to be saved.\nThrowing an exception will prevent saving and signal an error to the user.\n","properties":{"function":{"type":"string","description":"The name of the function to execute within the referenced script.\n\nThis property specifies which function to invoke from the script\nreferenced by _scriptId. The function will be called just before\nthe resource is saved.\n\nThe function must follow the expected signature and return the resource object.\n"},"_scriptId":{"type":"string","format":"objectId","description":"Reference to a predefined script resource containing the preSave function.\n\nThe referenced script should contain the function specified in the\n'function' property. This script must be accessible within the user's account\nand have appropriate permissions.\n"}}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"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":"Reference to the integration app that defines this resource.\n\nThis field is only populated for resources that are part of an integration app.\nIt contains the unique identifier (_id) of the integration app (connector)\nthat defines the structure, behavior, and templates for this resource.\n\nThe integration app is the published template that can be installed\nmultiple times across different accounts, with each installation creating\na separate integration instance (referenced by _integrationId).\n\nThis reference enables:\n- Identifying the source integration app for this resource\n- Determining which template version is being used\n- Linking to documentation, support, and marketplace information\n"}}},"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"}}},"APIM":{"type":"array","description":"Read-only field that stores information about the integration resources\npublished in the API Management (APIM) platform.\n\nThis field tracks the relationship between integrator.io resources and their\npublished counterparts in the APIM platform, which is\ntightly integrated with the Celigo UI. When resources are \"pushed\" to APIM,\nthis field is populated with the relevant identifiers and statuses.\n","items":{"type":"object","properties":{"apiId":{"type":"string","description":"Identifier for the API where this integrator.io resource is published in the APIM.\n\nThis is an APIM resource identifier (not prefixed with underscore like Celigo IDs)\nthat uniquely identifies the API in the API Management platform.\n"},"flowId":{"type":"string","description":"Identifier for the flow within the API where this integrator.io resource is linked.\n\nWhen an API has multiple integrator.io resources linked, each resource is associated\nwith a specific flow in the API, identified by this field. This is an APIM\nresource identifier.\n"},"status":{"type":"string","description":"Indicates the publishing stage of the integrator.io resource in APIM.\n\nPossible values:\n- 'oaspending': The resource is published but the OpenAPI Specification (OAS) is not\n  yet published. The apiId will be updated with the API ID created in APIM.\n- 'published': The OpenAPI Specification for the integrator.io resource has been\n  successfully uploaded to APIM.\n","enum":["oaspending","published"]}}}},"PreviewResponse":{"type":"object","description":"Response body for export data preview","properties":{"data":{"type":"array","description":"The data exported from source app","items":{"type":"object","description":"Individual data record from the source app"}},"dataURIs":{"type":"array","description":"URIs to the data in the source app","items":{"type":"string","description":"URI to a specific data record in the source app"}},"stages":{"type":"array","description":"Processing stages information","items":{"type":"object","description":"Information about a processing stage","properties":{"name":{"type":"string","description":"Name of the processing stage"},"errors":{"type":"array","description":"Errors encountered during this stage","items":{"type":"object","description":"Error information"}},"data":{"type":"array","description":"Data after being processed by this stage","items":{"type":"object","description":"Individual data record after being processed by this stage"}}}}}}},"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/integrations/{_integrationId}/flows/{_flowId}/exports/preview":{"post":{"summary":"Preview export data","description":"Preview export data from a specific export within a flow. This endpoint allows you to\npreview the data that would be exported, including the exported data, URIs to the data\nin the source app, and processing stages information.\n","operationId":"previewExportData","tags":["Exports"],"parameters":[{"name":"_integrationId","in":"path","required":true,"description":"The integration ID","schema":{"type":"string","format":"objectId"}},{"name":"_flowId","in":"path","required":true,"description":"The flow ID","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewRequest"}}}},"responses":{"200":{"description":"Successfully previewed export data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewResponse"}}}},"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"}}}}}}
````

## Invoke an export and return its data

> Runs an existing export end-to-end and returns the fetched data (or errors)\
> synchronously. Unlike \`POST /v1/flows/{\_id}/run\`, which starts a full flow\
> job, this endpoint invokes a \*\*single export\*\* in isolation and returns the\
> raw result directly in the response body.\
> \
> The request body is optional — pass \`{}\` or omit the body entirely for\
> exports that require no input. Some adaptor types accept a \`data\` array in\
> the body to supply input records.\
> \
> On success, the response contains the export's fetched data. On\
> application-level failure (e.g. the source system is unreachable), the\
> endpoint still returns a successful HTTP status with the errors in an\
> \`errors\` array — higher-level error codes are reserved for request-level\
> validation (bad ID, missing auth).\
> \
> This endpoint executes the export against the live source system.\
> \`POST /v1/exports/preview\` also queries the live source (reads only,\
> no job) — prefer it when you only need to inspect fetched records.

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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"]}}}}}},"paths":{"/v1/exports/{_id}/invoke":{"post":{"operationId":"invokeExport","tags":["Exports"],"summary":"Invoke an export and return its data","description":"Runs an existing export end-to-end and returns the fetched data (or errors)\nsynchronously. Unlike `POST /v1/flows/{_id}/run`, which starts a full flow\njob, this endpoint invokes a **single export** in isolation and returns the\nraw result directly in the response body.\n\nThe request body is optional — pass `{}` or omit the body entirely for\nexports that require no input. Some adaptor types accept a `data` array in\nthe body to supply input records.\n\nOn success, the response contains the export's fetched data. On\napplication-level failure (e.g. the source system is unreachable), the\nendpoint still returns a successful HTTP status with the errors in an\n`errors` array — higher-level error codes are reserved for request-level\nvalidation (bad ID, missing auth).\n\nThis endpoint executes the export against the live source system.\n`POST /v1/exports/preview` also queries the live source (reads only,\nno job) — prefer it when you only need to inspect fetched records.","parameters":[{"in":"path","name":"_id","required":true,"schema":{"type":"string","format":"objectId"},"description":"Export ID"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"Optional input payload. Most exports ignore the body; some accept\na `data` array of records to feed into the export pipeline.","properties":{"data":{"type":"array","description":"Input records for the export (adaptor-dependent)","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}},"responses":{"200":{"description":"Export completed. The response contains either the fetched data or an\n`errors` array if the export encountered application-level failures\n(connection timeout, file not found, etc.). Always inspect for errors\neven on 200.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"Export not found","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Server error — can occur when the export is misconfigured (e.g. a\nSimpleExport with no connection)."}}}}}}
```

## List dependencies of an export

> 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. Returns \`{}\` when no dependents exist, including for\
> well-formatted but nonexistent IDs.

```json
{"openapi":"3.2.0","info":{"title":"Exports","version":"1.0.0"},"tags":[{"name":"Exports","description":"Exports retrieve data from source systems — on a schedule, in delta mode, in real time,\non demand, or as a file/blob transfer — package the results into ≤ 5-MB pages, and pass\neach page to downstream flow steps. Depending on configuration, an export surfaces in the\nFlow Builder as an export, a real-time listener, a file transfer, or a mid-flow lookup.\n\n## Export schema\n\n{% openapi-schemas spec=\"export\" schemas=\"Export\" 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."},"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/exports/{_id}/dependencies":{"get":{"operationId":"listExportDependencies","tags":["Exports"],"summary":"List dependencies of an export","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. Returns `{}` when no dependents exist, including for\nwell-formatted but nonexistent IDs.","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"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.celigo.com/api/api-reference/exports.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
