configuring-exports — Claude Code skill: Celigo exports
A skill for configuring Celigo exports: connecting to an external system, picking an adaptor, delta exports, webhooks and lookup steps.
npx skills add celigo/ai --skill configuring-exports -a claude-codeWhat configuring-exports does
In Celigo an export is the data source of an integration. It connects to an external system and pulls records into the pipeline. It plays two roles: source, which fetches the primary batch of records, and lookup, a mid-flow enrichment step that fetches extra data per record.
The skill walks the whole execution pipeline: the API request or file read, response parsing through resourcePath, grouping, transformation, output filter and the preSavePage JavaScript hook. It also covers the three export categories — listeners (webhooks, AS2, distributed exports for NetSuite and Salesforce), change data capture via type: "stream", and scheduled pulls. Some details trip people up. resourcePath says where records live in the response, while a transform reshapes each record after extraction; they are separate steps. A wildcard like data[*].fieldName in a top-level fields[].extract is silently ignored and nothing gets merged.
Distributed exports need setup on the target side. NetSuite accounts require the Celigo SuiteApp or bundle; Salesforce needs the managed package plus an Apex trigger on each object. For a custom flow the customer deploys that trigger from the code shown on the export page. Trace keys are capped at 256 characters, and by default the export takes the first of the top-level fields id, internalId, _id — nested fields never qualify.
What it helps with
- pull records from an external system into a Celigo pipeline
- pick the right adaptor type for a target application
- switch a full export to a delta one
- receive pushed data through a webhook instead of polling
- enrich a record with fields from a lookup response mid-flow
Example prompts for the agent
- set up a NetSuite export with a delta on the lastModified field
- build a lookup export that fetches an order by ID and merges its status into the record
- add a webhook export that receives events from the external system
How to install configuring-exports
1Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a claude-code2Manually: put the files in place
~/.claude/skills/configuring-exports/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/configuring-exports/
1Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a codex2Manually: put the files in place
.agents/skills/configuring-exports/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a cursor2Manually: put the files in place
.cursor/skills/configuring-exports/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install celigo/ai configuring-exports2Manually: put the files in place
.github/skills/configuring-exports/SKILL.md1Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a gemini-cli2Platform CLI
gemini skills install https://github.com/celigo/ai --path skills/configuring-exportsManually: put the files in place
.devin/skills/configuring-exports/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about configuring-exports
How do I install configuring-exports in Claude?
Run npx skills add celigo/ai --skill configuring-exports -a claude-code. The skill file then lands at ~/.claude/skills/configuring-exports/SKILL.md.
What does configuring-exports do?
It helps the agent configure Celigo exports: choosing an adaptor type, setting resourcePath, transforms, filters and hooks, plus delta exports, webhooks and lookup steps.
How is a source export different from a lookup?
A source export fetches the primary batch of records at the start of a flow, while a lookup runs mid-flow and fetches data per record, marked with isLookup: true.
Source text
SKILL.md · MIT
---
name: configuring-exports
description: Configure Celigo export resources -- the data source step that fetches records from external systems. Use when creating or editing exports, choosing the right adaptor type for a target application, setting up delta (incremental) exports, webhooks, file transfers, or lookup steps. To replicate tables into a data warehouse, use building-syncs.
---
<!-- TIER:1 -->
# Configuring Exports
An export is the **data source** in a Celigo integration. It connects to an external system and pulls data into the pipeline. Exports serve two roles:
- **Source** -- the starting point that fetches the primary batch of records
- **Lookup** -- a mid-flow enrichment step (`isLookup: true`) that fetches additional data per-record during processing
Both roles are used across flows, APIs, and tools.
Beyond fetching data, exports also handle post-retrieval processing before records enter the pipeline:
- **Output filter** -- expression-based filtering to skip records that don't match criteria
- **Transform** -- Transformation 2.0 expression rules to reshape/flatten response data before mapping
- **preSavePage hook** -- JavaScript processing on the full page of records before they enter the pipeline; the only stage that can change how many records a page carries (split one record into many, or merge several)
- **One-to-many** -- when used as a lookup, fan out a child array already on the input record. Set `oneToMany: true` and `pathToMany` to that array path so each child triggers a separate lookup. Once fanned out, the array element itself is the record, and the parent (without the array) is `record._PARENT`. This is not `resourcePath`, which locates records in an API response -- see [One-to-many fan-out](#one-to-many-fan-out----the-array-element-is-the-record)
- **Response mapping** -- when used as a lookup, extract fields from the lookup response back into the record. Configured on the flow's `pageProcessors[]` entry, but planned when building the lookup export. The response contains a `data` array and an `errors` array. Use `data[0].fieldName` when you expect a single result (e.g., fetching one order by ID). When multiple results are expected, map the whole array with `extract: "data"` (downstream steps then read it as a normal JSON array, or fan out over it with one-to-many), or use a `lists` entry with `data[*].fieldName` extracts to build a reshaped array. Do not put `data[*].fieldName` in a top-level `fields[].extract` -- the wildcard is silently ignored there and nothing is merged. See [writing-mappings > Response Mapping Reference](../writing-mappings/SKILL.md#response-mapping-reference-transformation-10). Response mapping uses Transformation 1.0 syntax (extract/generate pairs), not the newer expression-based transforms
- **postResponseMap hook** -- JavaScript processing after response mapping merges the lookup response back into the record. Configured on the flow's `pageProcessors[]` entry, but planned when building the lookup export
- **Trace key** -- each record's identity downstream: imports use it to match retries to their errors and as their default lock key, and it never de-duplicates. By default it's the first of the top-level fields `id`, `internalId`, `_id`, `internal_id` or `identifier` (exact names, in a few capitalizations) that the record has -- never a nested field. Set `traceKeyTemplate` when the identity is nested or composite (`{{join "_" record.customerId record.orderId}}`, without the `record.` prefix when a transform reshaped the record first). Keys are capped at 256 characters
## Export Execution Pipeline
When a flow runs, each export executes this pipeline in strict order:
1. **API request / query / file read** -- fetches raw data from the external system. On a file export an optional `preParse` hook then gets the raw file text (`preParseData`, with `fileMeta`) and returns it for the parser; a throw there fails the run
2. **Response parsing** -- `resourcePath` extracts the record array from the response body or file (e.g., `http.response.resourcePath` for HTTP, `file.json.resourcePath` for JSON files, XPath for XML)
3. **Grouping** (optional) -- rows that share a key become one record, an array of those rows: `groupByFields`, or Group rows on a NetSuite saved search (see [Grouped records](#grouped-records----one-record-many-rows))
4. **Transformation** (optional) -- `transform` reshapes individual records after extraction (Transformation 2.0). On an HTTP export it also sees the response's headers, by lowercase name, so it can carry a header into the records: `{{{headers.[x-total-count]}}}` as an extract, or `$.headers['x-total-count']` with `inputContext: "envelope"` (live-verified in a preview and a test run, 2026-10-22). Use triple braces: double braces HTML-escape the value
5. **Output filter** (optional) -- discards records that don't match filter expression rules
6. **preSavePage hook** (optional) -- JavaScript processing on the full page of records
**Key distinction:** `resourcePath` tells the export WHERE to find records in the response. Transforms reshape WHAT each record looks like after extraction. When a user says "extract records from X" or "treat each X as a separate record", that's almost always a `resourcePath` change, not a transform. Use transforms when you need to flatten nested objects, rename fields, or restructure individual records.
## Three Categories of Export
Not all exports work the same way. Before building, understand which category you need:
### Listeners
Receive data pushed to Celigo from an external system. No polling, no scheduling -- the source system sends data when events happen.
- `WebhookExport` with `type: "webhook"` -- inbound HTTP listener (no connection required). URL, signature checks and responses: [Webhook listeners](#webhook-listeners----type-url-signature-responses)
- `AS2Export` -- AS2 EDI file reception
- Distributed exports (`type: "distributed"`) -- real-time listeners for NetSuite and Salesforce. NetSuite: saving the export deploys a Celigo user event script on the record type (the account needs the Celigo SuiteApp or bundle). Salesforce: saving creates nothing in Salesforce -- the org needs the Celigo managed package plus an Apex trigger on each object that calls it. Integration Apps create their triggers at installation; for a custom flow the customer deploys the trigger, starting from the code the export page shows under Required trigger. `celigo connections ping --distributed <connectionId>` checks that the package or SuiteApp responds; its `success: false` (still HTTP 200) also comes back for an offline connection, so read `resBody` before telling the user to install anything.
- Change data capture (`type: "stream"` plus a `cdc` object) -- streams database changes as they happen: MongoDB change streams (`MongodbExport`), and SQL Server CDC or PostgreSQL logical replication (`RDBMSExport`). A CDC export has no query. The RDBMS form watches `rdbms.tables` (`database.schema.table` on SQL Server, `schema.table` on PostgreSQL) or, on PostgreSQL only, `cdc.publicationName`. The save checks the export and the connection's database type, not the database: one whose own change capture isn't set up (PostgreSQL logical replication, SQL Server CDC on the database and each table, a MongoDB replica set) still saves, so when a CDC listener delivers nothing, check the database side first instead -- set one, not both. Every CDC export must resolve a snapshot mode (`cdc.snapshotMode`, or a `snapshot.mode` entry in `cdc.properties`), and a MongoDB one a capture mode too (`cdc.captureMode`, or a `capture.mode` entry). See [cdc.yml](references/schemas/cdc.yml).
- Topic listeners (`adaptorType: "TopicExport"`, `type: "stream"`) -- consume what is published to the Event Streams topic in `topic._topicId`. No `_connectionId` and no `cdc` object: with a connection, the save validates the export as that connection's adaptor and fails. Without `type: "stream"` the export saves but runs as a batch export and never starts on a publish; a PATCH can't add the type later, so update the full document with it, then disable and re-enable the flow. A topic listener can't be a lookup. See [topic.yml](references/schemas/topic.yml).
`type: "stream"` is accepted only on those three adaptors (`MongodbExport`, `RDBMSExport` on SQL Server or PostgreSQL, `TopicExport`); every other adaptor rejects the save with `unsupported_export_type`.
**A listener is switched by its flow.** `netsuite.distributed.disabled` is maintained by the platform; pause a NetSuite listener by disabling its flow. A topic subscription or a NetSuite listener's deployment becomes active when the flow goes from disabled to enabled -- a flow created already enabled doesn't activate it. Create the flow disabled and enable it afterwards. After repairing a listener export, or when a NetSuite listener stops firing, disable and re-enable the flow (`celigo flows set <flowId> disabled=true`, then `disabled=false`). A webhook listener has no such step: it accepts requests as soon as a flow it feeds is enabled, a flow created enabled included, and refuses them with 403 while every such flow is disabled.
**When to use:** The source system supports outbound webhooks, push notifications, or change data capture, or the records arrive on an Event Streams topic, and you want real-time processing.
### File Transfers
Read files from a remote location, then either parse them into records or transfer them as blobs.
- `FTPExport` / `S3Export` / `FileSystemExport` -- fetch files from FTP/SFTP, S3, or local filesystem
- `HTTPExport` with `http.type: "file"` -- read the files in a cloud storage folder (Google Drive, Box, Dropbox, Azure Blob Storage, Google Cloud Storage, Azure Data Lake Storage Gen2, Celigo Storage). On these file-storage connectors it's folder mode: `relativeURI` is a folder path the connector resolves, not an API endpoint -- an API URL there saves cleanly and fails at runtime with "Directory is not found". A folder picked in the UI's folder browser is stored in `file.directory` (`pathMode: "directoryId"` plus the provider's folder `id`); on the drive-style providers that id alone selects the folder and `relativeURI` isn't read, so retarget the export by changing `file.directory.id` (Google Cloud Storage keeps the bucket in `storageRootId` and the object prefix in `id`). The connector handles auth; the `file{}` config handles parsing. To fetch one file per record from an API endpoint instead, use a blob lookup (`type: "blob"`, `isLookup: true`) without `http.type: "file"`, and response-map its `data.0.blobKey` to `blobKey`, the field the upload import's `blobKeyPath` names.
- `NetSuiteExport` with `netsuite.type: "file"` -- fetch and parse files (CSV, JSON, XLSX, XML, EDI) from the NetSuite file cabinet
- Parsed mode (`file.output: "records"`) -- CSV, XML, JSON, XLSX, EDI files are parsed into individual records. Fixed-width files, and files whose rows carry a type marker (`HDR`/`DTL`), parse through a file definition (`file.type: "filedefinition"`); see [building-b2b](../building-b2b/SKILL.md#5-create-file-definitions), since a few rule mistakes drop rows without an error. On a file-provider export or lookup, each record's source file is also `fileMeta` -- exactly `fileName`, `fileSize` and `lastModifiedTime` (epoch milliseconds) -- read as `{{fileMeta.fileName}}` in Handlebars or `$.fileMeta.<field>` in an envelope-mode transform. Only file-provider steps populate it at run time, even where an editor render resolves it
- Blob mode (`type: "blob"`) -- binary files transferred as-is without parsing. Supported on HTTPExport, NetSuiteExport, SalesforceExport, FTPExport, and S3Export.
- **Source files are deleted after a successful read.** An FTP/SFTP or S3 export removes each file it processed from the folder or bucket unless `file.skipDelete` is `true`; `ftp.backupDirectoryPath` (S3: `s3.backupBucket`) moves them there instead, which also takes them out of the folder. Files that fail processing stay. When another system or flow reads the same files, set `file.skipDelete: true` and narrow the export to its own files with `ftp.fileNameStartsWith`/`fileNameEndsWith` (S3: `s3.keyStartsWith`/`keyEndsWith`).
A CSV export on SFTP that leaves the files for another reader (`hasHeaderRow` and a comma delimiter are the defaults, shown for clarity):
```json
{
"name": "Read inventory files",
"adaptorType": "FTPExport",
"_connectionId": "<ftpConnectionId>",
"ftp": { "directoryPath": "/outbound", "fileNameStartsWith": "inventory_", "fileNameEndsWith": ".csv" },
"file": { "type": "csv", "output": "records", "skipDelete": true, "csv": { "hasHeaderRow": true, "columnDelimiter": "," } }
}
```
**When to use:** The source system drops files (CSV, EDI, XML, etc.) into a directory, bucket, file cabinet, or cloud storage rather than exposing a record-based API.
### Record-Based Exports
Actively fetch batches of records from an API or database on a schedule.
- `HTTPExport` -- REST and GraphQL APIs (for GraphQL, see [GraphQL APIs](#graphql-apis----envelope-cursor-paging-errors-with-http-200))
- `NetSuiteHTTPExport` -- NetSuite's REST APIs on a `netsuite` connection: SuiteQL and REST record endpoints (`nsDomainType: "suitetalk"`) or a custom RESTlet (`nsDomainType: "restlet"`). Nothing has to exist in NetSuite first, so it's the default for NetSuite exports and lookups
- `NetSuiteExport` -- a saved search (or search criteria) run through Celigo's SuiteApp/bundle RESTlets. Use it when the user names or wants a saved search; it's also the adaptor for NetSuite listeners and file cabinet exports
- `SalesforceExport` -- SOQL/Bulk queries
- `RDBMSExport` -- SQL SELECT queries
- `MongodbExport`, `JDBCExport`, `DynamodbExport` -- other databases
- `WrapperExport` -- custom connector code, typically a function on a stack (`wrapper.function`)
**When to use:** You need to poll an API or query a database for records on a schedule (full fetch or delta/incremental).
## Quick Reference
### Adaptor Decision Matrix
| Your data comes from... | Use adaptorType | Category | Read schema |
|---|---|---|---|
| REST or GraphQL API | `HTTPExport` | Record-based | [http.yml](references/schemas/http.yml) |
| Files in a cloud storage folder (Google Drive, Box, Dropbox, Azure Blob, Google Cloud Storage, ADLS Gen2, Celigo Storage) | `HTTPExport` with `http.type: "file"` | File transfer | [http.yml](references/schemas/http.yml) + [file.yml](references/schemas/file.yml) |
| NetSuite records (SuiteQL, REST record endpoints, custom RESTlet) | `NetSuiteHTTPExport` + `nsDomainType` | Record-based | [http.yml](references/schemas/http.yml) |
| NetSuite saved search, listener, or file cabinet | `NetSuiteExport` | Record-based, Listener, or File transfer | [netsuite.yml](references/schemas/netsuite.yml) |
| Salesforce objects | `SalesforceExport` | Record-based | [salesforce.yml](references/schemas/salesforce.yml) |
| SQL database (queries, or CDC on SQL Server and PostgreSQL) | `RDBMSExport` | Record-based or Listener | [rdbms.yml](references/schemas/rdbms.yml) (+ [cdc.yml](references/schemas/cdc.yml) for CDC) |
| MongoDB (queries or change streams) | `MongodbExport` | Record-based or Listener | [mongodb.yml](references/schemas/mongodb.yml) (+ [cdc.yml](references/schemas/cdc.yml) for change streams) |
| JDBC database, including NetSuite through SuiteAnalytics Connect (a `netsuitejdbc` connection) | `JDBCExport` | Record-based | [jdbc.yml](references/schemas/jdbc.yml) |
| DynamoDB | `DynamodbExport` | Record-based | [dynamodb.yml](references/schemas/dynamodb.yml) |
| Files on FTP/SFTP | `FTPExport` | File transfer | [ftp.yml](references/schemas/ftp.yml) + [file.yml](references/schemas/file.yml) |
| Files on S3 | `S3Export` | File transfer | [s3.yml](references/schemas/s3.yml) + [file.yml](references/schemas/file.yml) |
| Webhooks / push events | `WebhookExport` | Listener | [webhook.yml](references/schemas/webhook.yml) |
| AS2 EDI messages | `AS2Export` | Listener | [as2.yml](references/schemas/as2.yml) |
| Event Streams topic | `TopicExport` (`type: "stream"`) | Listener | [topic.yml](references/schemas/topic.yml) |
| Manual file upload | `SimpleExport` | File transfer | [simple.yml](references/schemas/simple.yml) |
| Local filesystem | `FileSystemExport` | File transfer | [filesystem.yml](references/schemas/filesystem.yml) + [file.yml](references/schemas/file.yml) |
| Custom connector code on a stack | `WrapperExport` | Record-based | [wrapper.yml](references/schemas/wrapper.yml) |
**Raw HTTP is the fallback, not the default.** Pick the most specific match, in order:
1. **Native adaptor** -- if the application has its own row (NetSuite, Salesforce, databases, FTP/S3), use it. Do not build an `HTTPExport` against that app's REST API.
2. **Pre-built HTTP connector** -- for any other REST/GraphQL app, check the 550+ connector catalog before writing HTTP config (see [Check for a pre-built connector](#3-check-for-a-pre-built-connector)). The step is still an `HTTPExport`, but it runs on a connector-backed connection and takes its endpoint config from the connector.
3. **Manual HTTP** -- hand-write the config from public API docs only when no connector exists or it doesn't cover the endpoint you need.
`adaptorType` is **case-sensitive**: `HTTPExport`, not `httpExport`.
### Minimum Required Fields
Every export needs at minimum:
- `name` -- human-readable label
- `adaptorType` -- from the matrix above
- `_connectionId` -- except `WebhookExport`, `SimpleExport` and `TopicExport` (a connection on a topic listener fails the save)
- Adaptor config block -- `http{}`, `netsuite{}`, `ftp{}`, `salesforce{}`, `rdbms{}`, `topic{}`, etc.
### Which Schemas to Read
1. **Always:** [request.yml](references/schemas/request.yml) (base fields for all exports)
2. **Plus:** the adaptor-specific file from the matrix above (e.g., `http.yml` for HTTPExport)
3. **If file-based:** also [file.yml](references/schemas/file.yml) (CSV, XML, JSON, XLSX, EDI parsing config)
4. **If delta/incremental:** `type: "delta"`, plus [delta.yml](references/schemas/delta.yml) or the Handlebars URI pattern (`{{lastExportDateTime}}`)
5. **If cloning:** [clone-request.yml](references/schemas/clone-request.yml), [clone-response.yml](references/schemas/clone-response.yml)
### Schema Index
All schemas are in [references/schemas/](references/schemas/):
- **Base fields (all exports):** [request.yml](references/schemas/request.yml)
- **Response shape:** [response.yml](references/schemas/response.yml)
- **Adaptor-specific config:**
- [http.yml](references/schemas/http.yml) -- HTTP/REST/GraphQL
- [netsuite.yml](references/schemas/netsuite.yml) -- `NetSuiteExport` (saved search, Celigo RESTlets, listener, file cabinet); `NetSuiteHTTPExport` uses [http.yml](references/schemas/http.yml) plus `nsDomainType`
- [salesforce.yml](references/schemas/salesforce.yml) -- Salesforce (SOQL, bulk)
- [ftp.yml](references/schemas/ftp.yml) -- FTP/SFTP
- [s3.yml](references/schemas/s3.yml) -- Amazon S3
- [rdbms.yml](references/schemas/rdbms.yml) -- SQL databases
- [mongodb.yml](references/schemas/mongodb.yml) -- MongoDB
- [jdbc.yml](references/schemas/jdbc.yml) -- JDBC databases
- [dynamodb.yml](references/schemas/dynamodb.yml) -- DynamoDB
- [as2.yml](references/schemas/as2.yml) -- AS2 EDI
- [wrapper.yml](references/schemas/wrapper.yml) -- custom stack connectors
- [filesystem.yml](references/schemas/filesystem.yml) -- local filesystem
- [simple.yml](references/schemas/simple.yml) -- data loader / manual upload
- **File parsing:** [file.yml](references/schemas/file.yml) (CSV, XML, JSON, XLSX, EDI)
- **Grouping:** [group-by.yml](references/schemas/group-by.yml) (`groupByFields`; NetSuite saved searches group with `netsuite.skipGrouping` instead)
- **Operational modes:** [delta.yml](references/schemas/delta.yml), [once.yml](references/schemas/once.yml), [test.yml](references/schemas/test.yml), [webhook.yml](references/schemas/webhook.yml), [cdc.yml](references/schemas/cdc.yml) (database listeners), [topic.yml](references/schemas/topic.yml) (topic listeners). NetSuite and Salesforce listener settings live in `netsuite.distributed` and `salesforce.distributed` ([netsuite.yml](references/schemas/netsuite.yml), [salesforce.yml](references/schemas/salesforce.yml)); [distributed.yml](references/schemas/distributed.yml) holds only the optional `bearerToken` for pushing records into a distributed export
- **Mock output:** [mock-output.yml](references/schemas/mock-output.yml)
- **Preview request:** [preview-request.yml](references/schemas/preview-request.yml) (`postData` sets the delta variables in a preview)
- **Clone:** [clone-request.yml](references/schemas/clone-request.yml), [clone-response.yml](references/schemas/clone-response.yml)
## Related Skills
- [configuring-connections > Quick Reference](../configuring-connections/SKILL.md#quick-reference) -- connection types, auth methods, iClients
- [managing-file-storage > Use stored files in a flow](../managing-file-storage/SKILL.md#8-use-stored-files-in-a-flow) -- Celigo Storage folders as a file source
- [writing-mappings > Transformation 2.0](../writing-mappings/SKILL.md#transformation-20-workflow) -- reshape export output before mapping
- [writing-scripts > Data Pipeline Hooks](../writing-scripts/SKILL.md#data-pipeline-hooks) -- preSavePage, postResponseMap hooks
- [writing-handlebars > Quick Reference](../writing-handlebars/SKILL.md#quick-reference) -- dynamic values in URIs, filters, delta tokens
- [building-flows > How to Build a Flow](../building-flows/SKILL.md#how-to-build-a-flow) -- wiring exports into flows
- [configuring-topics > How to Build an Event Stream](../configuring-topics/SKILL.md#how-to-build-an-event-stream) -- the topic a listener reads: registration, retention, messages, positions
- [building-syncs > Sources](../building-syncs/SKILL.md#sources-catalog-datasets-and-export-backed-datasets) -- an export as the source of a sync's export-backed dataset
- [troubleshooting-flows > Diagnostic Workflow](../troubleshooting-flows/SKILL.md#diagnostic-workflow) -- diagnosing export-related failures
<!-- TIER:2 -->
## How to Build an Export
### 1. Identify the target application
What system are you pulling data from? This determines everything -- adaptor type, connection type, and configuration shape.
### 2. Check for existing patterns
Before building from scratch, look at what already exists:
```bash
# Search across the entire account for related resources
celigo account search "<keyword>"
# Show what an existing export uses (connection) and what uses it (flows)
celigo account dependencies export <id>
# Find orphaned exports not referenced by any flow
celigo account lint
# Check if a similar export already exists in the account
celigo exports list | grep -i "<application-name>"
# Search the marketplace for pre-built integration templates
celigo templates marketplace
# Preview a template to see its export configuration
celigo templates preview <id> --model Export
celigo templates preview <id> --summary
```
The account index auto-refreshes when stale (older than 15 minutes by default). Force a fresh snapshot with `celigo account snapshot`.
Existing exports in the account are the best reference -- they show proven patterns for that specific customer's setup. Marketplace templates may provide a complete pre-built integration you can install rather than building from scratch.
### 3. Check for a pre-built connector
**Always run this check before writing any HTTP config.** Celigo maintains 550+ HTTP connector definitions and 590+ trading partner connectors. These provide pre-configured auth, base URLs, and endpoint definitions for common applications. Connectors are set on the **connection**, not the export -- but they determine what the export can do. Hand-write a manual `HTTPExport` from public API docs only when this search comes up empty or the connector doesn't cover the endpoint you need.
```bash
# Search HTTP connectors (REST APIs: Shopify, Stripe, HubSpot, etc.)
celigo http-connectors list | grep -i "<application-name>"
celigo http-connectors get <id> --full # see endpoints, resources, auth config
# Drill into the endpoints the connector defines for exports
celigo http-connectors catalog <id> --resource-type export --published-only
celigo http-connectors endpoint-detail <id> --resource-type export --resource-id <rid> --endpoint-id <epid>
# Search trading partner connectors (EDI, AS2, VAN)
celigo tp-connectors list
```
If an HTTP connector exists for your target app, create the connection from it (`http._httpConnectorId` -- see [configuring-connections > Check for a pre-built connector and global iClient](../configuring-connections/SKILL.md#4-check-for-a-pre-built-connector-and-global-iclient)) and take the export's `relativeURI`, method, pagination, and response paths from the connector's endpoint metadata rather than reconstructing them from public API docs. In `celigo http-connectors endpoint-detail`, the endpoint's `supportedBy` lists what the connector's own form applies: `preConfiguredFields` (values it sets), `fieldsUserMustSet` (what it asks the user for -- often which `type` the endpoint supports, such as `delta` or `test`) and `fieldsToUnset`. Their paths are the form's, not the export's: Shopify's list-customers endpoint presets `response` to `{resourcePath: "customers"}` (the export's `http.response.resourcePath`) and `delta` to a `dateFormat` (`delta.dateFormat`) plus `defaults: {updated_at_min: "{{{lastExportDateTime}}}"}` (a query parameter in `relativeURI`). Saving links the export to the connector: when `relativeURI` and `method` match one of its endpoints, the platform sets `http._httpConnectorVersionId`, `http._httpConnectorResourceId` and `http._httpConnectorEndpointId`, replacing pointers that belong to another connector. Pointers for the connection's own connector are kept exactly as sent, even when the URI names a different endpoint. Read the export back after saving (no pointers means the URI matched no endpoint), and when you retarget it to another endpoint, update or drop the old pointers in the same save: the request follows `relativeURI`, but stale pointers keep naming the old endpoint in the editor and in later edits.
If a trading partner connector exists (EDI/AS2), reference it on the export via `ftp._tpConnectorId` (FTP exports) or `as2._tpConnectorId` (AS2 exports). You may also need to set `_ediProfileId` on the export for EDI document validation.
### 4. Query metadata for the target system
For NetSuite, Salesforce, and RDBMS connections, you can discover available record types and fields directly from the live system:
```bash
# List available record types / sObjects / tables
# NetSuite also returns saved searches alongside record types
celigo metadata types <connectionId>
# List fields for a specific entity type
celigo metadata fields <connectionId> <entityType>
```
This tells you what data is available to export before you write any configuration. Both commands read a server-side cache: after a field, record type or saved search is created in the app, re-read with `--refresh`.
- **NetSuite:** `metadata types` returns both record types and saved searches (with IDs you need for `netsuite.restlet.searchId`). Use a record type's lowercase `scriptId` as `recordType`, not its `id`: for custom records and lists, `id` is NetSuite's numeric internal id. A search over every transaction type uses `recordType: "transaction"`. `metadata fields` returns field IDs, names, types, and group — including the sublist groups and fields you'll need for `netsuite_da.mapping.lists[]` on a NetSuite DA import. Search criteria and columns take search-column ids instead, which can differ (`shipaddress1`, not `shipaddr1`).
- **Salesforce:** `metadata types` returns sObjects with queryable/createable flags. `metadata fields` returns fields, types, and relationship names — use these to discover child objects for `salesforce.distributed.relatedLists[]` and relationship field names for cross-object queries.
- **RDBMS:** `metadata types` returns table names. `metadata fields` returns column names and types for a given table — use these when writing SQL queries or building field mappings.
### 5. Determine the category
Is this a **listener** (real-time push from the source), a **file transfer** (fetch and parse/transfer files), or a **record-based export** (poll an API or query a database)? This narrows which adaptor types and modes apply.
### 6. Choose the right adaptor type
Use the [Adaptor Decision Matrix](#adaptor-decision-matrix) in Quick Reference above to select the correct `adaptorType` for your target system. For NetSuite, [Diagnosing NetSuite Steps](references/netsuite.md) has the checks to run against the NetSuite account and the errors its steps return.
### 7. Build the export JSON
Use the [Schema Index](#schema-index) and [Which Schemas to Read](#which-schemas-to-read) in Quick Reference above. Read `request.yml` for base fields, then the adaptor-specific schema, plus `file.yml` if file-based and `delta.yml` if incremental.
## Export Design Decisions
A few design choices recur when building exports. Each has a defensible default once the framing is clear.
### Delta vs one-time vs full sync
The export's `type` field selects the sync behavior:
- **Delta** (`type: "delta"`) -- pulls only records created or modified since the flow's checkpoint (see [Delta windows and the checkpoint](#delta-windows-and-the-checkpoint)). The default for ongoing scheduled syncs when the source exposes a usable "last modified" timestamp. Application adaptors such as NetSuite and Salesforce name the timestamp field in `delta.dateField`; HTTP exports and SQL queries put `{{lastExportDateTime}}` in the request instead (`relativeURI`, body or query), and an HTTP export with `delta.dat...
© celigo · MIT · celigo/ai