How to Create a Salesforce Export with Celigo CLI
Learn how to create a Salesforce export with the Celigo CLI, define a SOQL query to extract account data, enable delta sync, and attach the export to an existing flow.
Learn how to create a Salesforce export with the Celigo CLI, define a SOQL query to extract account data, enable delta sync, and attach the export to an existing flow.
With the flow in place, the next step is to create a Salesforce export that queries account data with SOQL. If you haven’t created the flow yet, start with How to Create a Flow with Celigo CLI.
Define the export in JSON with adaptorType, _connectionId, and a SOQL query,
then create it with celigo exports create. Attach the export to the flow
through the flow definition’s pageGenerators, then enable delta sync with
type: "delta" so each run pulls only records modified since the last
successful run.
Exports are referenced, not contained. The export points to its connection with
_connectionId, and the flow points back to the export with
pageGenerators[]._exportId. Keeping those two relationships straight is most
of the work in this post.
From salesforce-google-sheets-integration, create an exports directory for
export definitions.
cd salesforce-google-sheets-integration
mkdir exports
cd exports
Create the export definition as
celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
vim celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
Three parts do the real work here. The adaptorType identifies the connector,
the _connectionId references the Salesforce connection created earlier in the
series, and the salesforce block holds the query configuration. The SOQL query
selects the account fields, resolves Owner.Name through the owner
relationship, and fetches related contacts through a subquery.
{
"_connectionId": "<YOUR_SALESFORCE_CONNECTION_ID>",
"name": "Fetch Salesforce Account by Name and Last Modified Date",
"description": "For https://rjleyva.com Celigo CLI demonstration only.",
"adaptorType": "SalesforceExport",
"salesforce": {
"api": "rest",
"type": "soql",
"soql": {
"query": "SELECT Id, Name, Owner.Name, LastModifiedDate, (SELECT Id, Name, Email FROM Contacts) FROM Account WHERE Owner.Name IN ('RJ Leyva')"
}
},
"includeDeletedRecords": false
}
Inside the salesforce block, type selects the extraction method, and soql
queries the org through the REST API. includeDeletedRecords: false leaves
deleted and archived records out of the results. Don’t confuse this nested
type with a second, top-level type field that gets added later in this post
to select sync behavior.
Create the export by redirecting the definition file to the CLI.
celigo exports create < celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
Once the command completes successfully, the export exists in integrator.io, and the CLI returns the assigned ID, timestamps, name, and other resource properties.
~/Developer/salesforce-google-sheets-integration/exports ❯ celigo exports create < celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
_id <YOUR_EXPORT_ID>
createdAt 2026-08-22T19:30:27.422Z
lastModified 2026-08-22T19:30:27.474Z
name Fetch Salesforce Account by Name and Last Modified Date
description For https://rjleyva.com Celigo CLI demonstration only.
_connectionId <YOUR_SALESFORCE_CONNECTION_ID>
apiIdentifier <YOUR_API_IDENTIFIER>
asynchronous true
salesforce {
"type": "soql",
"api": "rest",
"soql": {
"query": "SELECT Id, Name, Owner.Name, LastModifiedDate, (SELECT Id, Name, Email FROM Contacts) FROM Account WHERE Owner.Name IN ('RJ Leyva')"
}
}
adaptorType SalesforceExport
Add the _id back into the definition so the file matches the created resource.
The next section needs both IDs, the flow’s and the export’s.
A flow starts with one or more page generators. Each entry in the flow
definition’s pageGenerators array references an export by _exportId, making
that export the source of records for the flow.
Open the flow definition from the previous post.
cd ../flows
vim celigo-cli-demo-only-salesforce-accounts-to-google-sheets.json
Add the pageGenerators array referencing the export created above.
{
"_id": "<YOUR_FLOW_ID>",
"_integrationId": "<YOUR_INTEGRATION_ID>",
"name": "Salesforce Accounts to Google Sheets",
"description": "For https://rjleyva.com Celigo CLI demonstration only.",
"disabled": true,
"pageGenerators": [
{
"_exportId": "<YOUR_EXPORT_ID>"
}
]
}
NOTE: The attachment key is
_exportId, not_integrationId. Both resources carry an_integrationIdbecause both belong to the integration. That field describes ownership, not attachment.
Update the existing flow with the modified definition.
celigo flows update <YOUR_FLOW_ID> --file celigo-cli-demo-only-salesforce-accounts-to-google-sheets.json
Like the connection update in a previous post, flows update sends a full
replacement, so the definition must stay complete. The --file flag reads the
body from the named file rather than piping it on stdin. The command returns the
updated flow, now carrying the page generator.
~/Developer/salesforce-google-sheets-integration/flows ❯ celigo flows update <YOUR_FLOW_ID> --file celigo-cli-demo-only-salesforce-accounts-to-google-sheets.json
_id <YOUR_FLOW_ID>
lastModified 2026-08-22T20:04:32.888Z
name Salesforce Accounts to Google Sheets
description For https://rjleyva.com Celigo CLI demonstration only.
disabled true
_integrationId <YOUR_INTEGRATION_ID>
createdAt 2026-08-22T19:42:37.940Z
autoResolveMatchingTraceKeys true
logging {
"mode": "accountLevel"
}
If you reference the wrong flow ID, the API rejects the request before anything changes.
(404): Not found: Flow not found.
Hint: A referenced id in the request doesn't exist. Verify the ids you passed (e.g. _connectionId, _exportId, _importId, _flowId).
List flows to confirm the ID when this happens.
celigo flows list --format json
The query currently returns every account owned by the named owner on every run,
whether or not anything changed. Adding a filter against
{{lastExportDateTime}} turns the export into a delta sync. That handlebar
resolves at runtime to the timestamp of the export’s last successful run.
Return to the exports directory and open the export definition.
cd ../exports
vim celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
Add the sync mode and the new query clause. Alongside _connectionId, the
definition now carries the _id returned by create and the _integrationId
shared with the flow.
{
"_id": "<YOUR_EXPORT_ID>",
"_integrationId": "<YOUR_INTEGRATION_ID>",
"_connectionId": "<YOUR_SALESFORCE_CONNECTION_ID>",
"name": "Fetch Salesforce Account by Name and Last Modified Date",
"description": "For https://rjleyva.com Celigo CLI demonstration only.",
"adaptorType": "SalesforceExport",
"type": "delta",
"delta": {
"dateField": "LastModifiedDate"
},
"salesforce": {
"api": "rest",
"type": "soql",
"soql": {
"query": "SELECT Id, Name, Owner.Name, LastModifiedDate, (SELECT Id, Name, Email FROM Contacts) FROM Account WHERE Owner.Name IN ('RJ Leyva') AND LastModifiedDate > {{lastExportDateTime}}"
}
},
"includeDeletedRecords": false
}
Setting type: "delta" on the resource is what makes {{lastExportDateTime}}
resolvable. Without it, the platform has no checkpoint to bind the handlebar
against.
NOTE:
delta.dateFielddoes not modify a manual SOQL query. The WHERE clause does the filtering. The field satisfies validation and mirrors what the integrator.io UI sets when you pick the delta export type.
Update the export with the modified definition.
celigo exports update <YOUR_EXPORT_ID> --file celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
With delta enabled, the first run behaves like a full export because no checkpoint exists yet. Each subsequent run pulls only records modified since the last successful run, and after a failed run the checkpoint stays put so no changed records are missed.
You can run an export on demand without starting the flow.
celigo exports invoke <YOUR_EXPORT_ID>
invoke executes the SOQL query against Salesforce through the connection and
returns the records it finds, without creating a flow job. This catches query
and connection problems before they reach a flow run. Your records will differ
depending on your org data.
~/Developer/salesforce-google-sheets-integration/exports ❯ celigo exports invoke <YOUR_EXPORT_ID>
[
{
"Id": "<YOUR_ACCOUNT_ID>",
"Name": "Company XYZ",
"Owner": {
"Name": "RJ Leyva"
},
"LastModifiedDate": "2026-08-22T21:14:31.000Z",
"Contacts": {
"records": [
{
"Id": "<YOUR_CONTACT_ID>",
"Name": "John Doe",
"Email": "john.doe@xyz.com"
}
]
}
}
]
At this point, your integration structure should look like this.
~/Developer/salesforce-google-sheets-integration ❯ tree
.
├── connections
│ ├── celigo-cli-demo-only-google-sheets-connection.json
│ └── celigo-cli-demo-only-salesforce-connection.json
├── exports
│ └── celigo-cli-demo-only-fetch-salesforce-account-by-name-and-last-modified-date.json
├── flows
│ └── celigo-cli-demo-only-salesforce-accounts-to-google-sheets.json
└── integrations.json
The flow now has a source. In the next post, How to Create a Google Sheets Import with Celigo CLI we’ll create the Google Sheets import as its destination and map the account fields into spreadsheet rows.