configuring-exports — скилл для Claude Code: экспорты Celigo
Скилл для настройки экспортов в Celigo: подключение к внешней системе, выбор адаптора, дельта-выгрузки, вебхуки и lookup-шаги.
npx skills add celigo/ai --skill configuring-exports -a claude-codeЧто делает configuring-exports
Экспорт в Celigo — это источник данных интеграции. Он подключается к внешней системе и тянет записи в пайплайн. Роль может быть двух видов: источник, который забирает основную партию записей, и lookup — промежуточный шаг обогащения, когда данные подтягиваются по каждой записи отдельно.
Скилл ведёт по всему конвейеру выполнения: запрос к API или чтение файла, разбор ответа через resourcePath, группировка строк, трансформация, фильтр вывода и хук preSavePage на JavaScript. Отдельно разбираются три категории экспортов: слушатели (вебхуки, AS2, распределённые экспорты для NetSuite и Salesforce), change data capture через type: "stream" и обычные выгрузки по расписанию. Есть нюансы, на которых легко ошибиться: resourcePath указывает, где искать записи, а трансформация меняет их форму — это разные шаги. Дикая карта в data[*].fieldName на верхнем уровне fields[].extract молча игнорируется, и ничего не смёржится.
Распределённые экспорты требуют подготовки на стороне целевой системы. Для NetSuite аккаунту нужен Celigo SuiteApp или bundle, для Salesforce — managed package и Apex-триггер на каждом объекте. Триггер для кастомного потока разворачивает сам клиент, взяв код со страницы экспорта. Ключ трассировки ограничен 256 символами, а по умолчанию берётся первое из полей id, internalId, _id верхнего уровня — вложенные поля не подставляются.
Какие задачи решает
- собрать выгрузку записей из внешней системы в пайплайн Celigo
- выбрать подходящий тип адаптора под целевое приложение
- настроить дельта-выгрузку вместо полной
- принять входящие данные через вебхук без опроса источника
- обогатить запись данными из lookup-ответа по ходу потока
Примеры запросов агенту
- настрой экспорт из NetSuite с дельта-выгрузкой по полю lastModified
- сделай lookup-экспорт, который подтягивает заказ по ID и мёржит поле status в запись
- добавь вебхук-экспорт, который принимает события от внешней системы
Как установить configuring-exports
1Через Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a claude-code2Вручную: положить файлы
~/.claude/skills/configuring-exports/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/configuring-exports/
1Через Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a codex2Вручную: положить файлы
.agents/skills/configuring-exports/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a cursor2Вручную: положить файлы
.cursor/skills/configuring-exports/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install celigo/ai configuring-exports2Вручную: положить файлы
.github/skills/configuring-exports/SKILL.md1Через Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a gemini-cli2Командой платформы
gemini skills install https://github.com/celigo/ai --path skills/configuring-exportsВручную: положить файлы
.devin/skills/configuring-exports/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add celigo/ai --skill configuring-exports -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о configuring-exports
Как установить configuring-exports в Claude?
Выполните npx skills add celigo/ai --skill configuring-exports -a claude-code. После этого файл скилла окажется в ~/.claude/skills/configuring-exports/SKILL.md.
Что делает configuring-exports?
Помогает агенту настраивать экспорты Celigo: выбирать тип адаптора, задавать resourcePath, трансформации, фильтры и хуки, а также дельта-выгрузки, вебхуки и lookup-шаги.
Чем экспорт-источник отличается от lookup?
Источник забирает основную партию записей в начале потока, а lookup работает в середине и подтягивает данные по каждой записи отдельно, помечаясь isLookup: true.
Исходный текст
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