Skip to Content

Loaders API

Loaders are inbound ELT (Extract, Load, Transform) configurations that pull data from external SaaS tools and databases into your data warehouse (Source). They complement Sources by bringing data into the warehouse, while Sources provide read access from the warehouse.

Endpoints

MethodPathDescription
GET/api/v1/workspaces/{id}/loadersList all loaders
POST/api/v1/workspaces/{id}/loadersCreate a loader
GET/api/v1/workspaces/{id}/loaders/{loaderId}Get a loader
PUT/api/v1/workspaces/{id}/loaders/{loaderId}Update a loader
DELETE/api/v1/workspaces/{id}/loaders/{loaderId}Delete a loader
POST/api/v1/workspaces/{id}/loaders/{loaderId}/triggerTrigger a sync run
GET/api/v1/workspaces/{id}/loaders/{loaderId}/runsList loader runs
GET/api/v1/workspaces/{id}/loaders/{loaderId}/runs/{runId}Get a loader run
GET/api/v1/loader-typesList available loader types (global catalog)
POST/api/v1/workspaces/{id}/loaders/testTest a new loader connection
POST/api/v1/workspaces/{id}/loaders/{loaderId}/testTest an existing loader connection
POST/api/v1/workspaces/{id}/loaders/discoverDiscover available streams for new credentials
POST/api/v1/workspaces/{id}/loaders/{loaderId}/discoverDiscover new streams for an existing loader
POST/api/v1/workspaces/{id}/loaders/{loaderId}/runs/{runId}/cancelCancel a running loader run

List Loaders

GET /api/v1/workspaces/{id}/loaders

Returns all loaders in the workspace.

Response

[ { "id": "550e8400-e29b-41d4-a716-446655440000", "workspace_id": "660e8400-e29b-41d4-a716-446655440000", "source_id": "770e8400-e29b-41d4-a716-446655440000", "name": "Service Cloud", "loader_type": "salesforce_service_cloud", "config": { "instance_url": "https://mycompany.my.salesforce.com", "api_version": "v59.0" }, "target_schema": "SALESFORCE_RAW", "selected_streams": ["Case", "CaseHistory", "CaseTeamMember", "Contact"], "sync_mode": "incremental", "stream_sync_modes": { "Case": "incremental_merge", "CaseTeamMember": "full_refresh", "Contact": "incremental_merge" }, "primary_keys": {}, "change_detection": {}, "schedule": "0 */6 * * *", "status": "active", "status_error": "", "created_by": "880e8400-e29b-41d4-a716-446655440000", "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z", "last_run_at": "2024-01-15T15:00:00Z", "last_run_id": "990e8400-e29b-41d4-a716-446655440000", "last_run_status": "completed" } ]

In this example CaseHistory has no entry in stream_sync_modes, so it runs in the loader-wide sync_mode (incremental, append); the other three streams run in their own mode. See Sync modes.

Example

curl -X GET https://agentic.zeotap.com/api/v1/workspaces/{id}/loaders \ -H "Authorization: Bearer <token>" \ -H "X-Workspace-ID: <workspace-id>"

Create Loader

POST /api/v1/workspaces/{id}/loaders

Creates a new loader to pull data from an external source into a warehouse.

Request Body

FieldTypeRequiredDescription
namestringYesDisplay name
loader_typestringYesLoader connector type (see List Loader Types)
source_idstring (UUID)YesTarget warehouse source to load data into
configobjectYesConnection configuration (varies by loader type)
credentialsobjectDepends on typeSecret credentials (API keys, tokens). For an OAuth loader, send {"credential_ref": "<ref>"} with the reference returned by the OAuth connect flow. Stored encrypted and never returned.
target_schemastringNoSchema in the warehouse to write tables to. Default: cdp_raw
selected_streamsarray of stringYesNames of the streams to load, as returned by Discover Streams
sync_modestringNoLoader-wide default sync mode: full_refresh, incremental (append) or incremental_merge (merge on key). Default: incremental. Used by every stream with no entry in stream_sync_modes
stream_sync_modesobjectNoStream name → sync mode, for streams that run in a mode other than sync_mode. Omitted: filled in from the connector’s recommended mode for each selected stream (default_sync_mode on Discover Streams). Sent: used exactly as given — {} means every stream follows sync_mode
primary_keysobjectNoStream name → array of column names that incremental_merge upserts on, overriding the key the connector declares
change_detectionobjectNoStream name → how the stream’s incremental reads detect change (warehouse loaders). See Change detection
schedulestringNoCron expression (UTC). Empty or omitted: runs only when triggered

Supported Loader Types

GET /api/v1/loader-types returns the full catalog, including each type’s configuration schema. Commonly used types:

Supported Loader Types

TypeDescription
salesforceSalesforce Sales Cloud objects
salesforce_service_cloudSalesforce Service Cloud objects
hubspotHubSpot CRM objects
stripeStripe payment data
shopifyShopify e-commerce data
ga4Google Analytics 4
facebook_adsFacebook Ads campaigns and performance
google_adsGoogle Ads campaigns and performance
linkedin_adsLinkedIn Ads campaigns
klaviyoKlaviyo email marketing
mailchimpMailchimp email marketing
postgresqlPostgreSQL database
mysqlMySQL database
rest_apiCustom REST API
google_sheetsGoogle Sheets
s3Amazon S3 files

Example

curl -X POST https://agentic.zeotap.com/api/v1/workspaces/{id}/loaders \ -H "Authorization: Bearer <token>" \ -H "X-Workspace-ID: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{ "name": "Service Cloud", "loader_type": "salesforce_service_cloud", "source_id": "770e8400-e29b-41d4-a716-446655440000", "config": { "instance_url": "https://mycompany.my.salesforce.com", "api_version": "v59.0" }, "credentials": {"credential_ref": "<ref from the OAuth connect flow>"}, "target_schema": "SALESFORCE_RAW", "selected_streams": ["Case", "CaseHistory", "CaseTeamMember", "Contact"], "sync_mode": "incremental", "schedule": "0 */6 * * *" }'

The request omits stream_sync_modes, so each selected stream gets the Service Cloud loader’s recommended mode, and the response stores only the streams whose mode differs from sync_mode:

{ "id": "550e8400-e29b-41d4-a716-446655440000", "sync_mode": "incremental", "stream_sync_modes": { "Case": "incremental_merge", "CaseTeamMember": "full_refresh", "Contact": "incremental_merge" }, "...": "remaining loader fields" }

To choose the modes yourself, send stream_sync_modes explicitly — it then replaces the recommendations entirely:

{ "sync_mode": "incremental_merge", "stream_sync_modes": {"CaseHistory": "incremental"} }

Returns 201 Created with the loader object.


Get Loader

GET /api/v1/workspaces/{id}/loaders/{loaderId}

Returns a single loader by ID.


Update Loader

PUT /api/v1/workspaces/{id}/loaders/{loaderId}

Updates an existing loader configuration.

Request Body

FieldTypeRequiredWhen omitted
namestringYes—
configobjectYes— (the full configuration is replaced)
selected_streamsarray of stringYes— (the list is replaced)
target_schemastringNoReset to cdp_raw — send the current value to keep it
credentialsobjectNoStored credentials kept. When sent, the fields you send are merged over the stored ones
sync_modestringNoStored value kept
stream_sync_modesobjectNoStored map kept. Send {} to clear it, so every stream follows sync_mode
primary_keysobjectNoStored map kept. Send {} to clear it
change_detectionobjectNoStored map kept. Send {} to clear it
schedulestringNoStored schedule kept. Send "" to clear it (manual runs only)

Connector-recommended modes are applied only on create. An update never fills stream_sync_modes from the connector, so a loader’s tables only change mode when you change it. An entry for a stream you deselect is dropped along with the stream.

Example

Run CaseHistory as append and leave every other setting as stored:

curl -X PUT https://agentic.zeotap.com/api/v1/workspaces/{id}/loaders/{loaderId} \ -H "Authorization: Bearer <token>" \ -H "X-Workspace-ID: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{ "name": "Service Cloud", "config": { "instance_url": "https://mycompany.my.salesforce.com", "api_version": "v59.0" }, "target_schema": "SALESFORCE_RAW", "selected_streams": ["Case", "CaseHistory", "CaseTeamMember", "Contact"], "stream_sync_modes": { "Case": "incremental_merge", "CaseHistory": "incremental", "CaseTeamMember": "full_refresh", "Contact": "incremental_merge" } }'

stream_sync_modes is replaced as a whole, so send every entry you want to keep.

Returns 200 OK with the loader object.


Sync Modes

A stream’s effective sync mode is stream_sync_modes[stream] if the map has an entry for it, otherwise the loader’s sync_mode.

ValueBehaviour
full_refreshEach run reads the stream in full and replaces the table
incrementalEach run reads records changed since the stored cursor and appends them
incremental_mergeReads like incremental, then upserts on the stream’s primary key (primary_keys[stream], else the connector’s declared key, else an id column)

Validation, applied on create and update (a violation returns 400):

  • every key in stream_sync_modes, primary_keys and change_detection must be one of selected_streams;
  • every value in stream_sync_modes must be one of the three modes above;
  • change_detection rules that depend on the sync mode are checked against each stream’s effective mode.

A stream that cannot be read incrementally (no cursor — supports_incremental: false on Discover Streams) is read in full on every run whatever its mode. Under incremental that appends a complete copy of the stream every run, so give such streams full_refresh (or incremental_merge, which keeps one row per key but never removes rows deleted at the source).

Loaders created before per-stream modes existed have stream_sync_modes: {} and run every stream in sync_mode.

Change Detection

change_detection maps a stream to an object describing how its incremental reads detect change. Streams with no entry read on a timestamp cursor, which is the default.

FieldValuesDescription
modecursor (default), native_cdcnative_cdc reads the source warehouse’s own change feed (loader types that support it)
cursor_fieldcolumn namecursor mode only: the column the cursor compares, for loader types that let you choose it
includeall_changes (default), inserts_onlynative_cdc only. all_changes needs the stream’s effective mode to be incremental_merge
on_deletehard (default), soft, ignorenative_cdc with all_changes only: how a deletion is applied to the target

native_cdc needs an incremental effective mode, and with incremental_merge it also needs primary_keys for the stream.


Delete Loader

DELETE /api/v1/workspaces/{id}/loaders/{loaderId}

Deletes a loader.

Response

{ "status": "deleted" }

Trigger Sync Run

POST /api/v1/workspaces/{id}/loaders/{loaderId}/trigger

Manually triggers a loader sync run.

Response

Returns the created loader run object with status 201 Created.

Example

curl -X POST https://agentic.zeotap.com/api/v1/workspaces/{id}/loaders/{loaderId}/trigger \ -H "Authorization: Bearer <token>" \ -H "X-Workspace-ID: <workspace-id>"

List Loader Runs

GET /api/v1/workspaces/{id}/loaders/{loaderId}/runs

Returns the execution history for a loader.

Response

[ { "id": "aae8400-e29b-41d4-a716-446655440000", "loader_id": "550e8400-e29b-41d4-a716-446655440000", "workspace_id": "660e8400-e29b-41d4-a716-446655440000", "status": "completed", "started_at": "2024-01-15T15:00:00Z", "completed_at": "2024-01-15T15:05:30Z", "rows_loaded": 15420, "streams_total": 2, "streams_failed": 0, "error_message": "", "triggered_by": "880e8400-e29b-41d4-a716-446655440000", "created_at": "2024-01-15T15:00:00Z" } ]

Loader Run Statuses

StatusDescription
pendingRun is queued
runningRun is in progress
completedRun finished successfully
failedRun failed with an error
cancelledRun was cancelled

Get Loader Run

GET /api/v1/workspaces/{id}/loaders/{loaderId}/runs/{runId}

Returns details of a specific loader run.


Discover Streams

POST /api/v1/workspaces/{id}/loaders/discover (body: loader_type, config, credentials) or POST /api/v1/workspaces/{id}/loaders/{loaderId}/discover (stored configuration)

Returns the streams the loader can read with these credentials.

{ "streams": [ { "name": "CaseHistory", "label": "Case History", "columns": [ {"name": "Id", "type": "string", "nullable": false}, {"name": "CreatedDate", "type": "timestamp", "nullable": true} ], "cursor_field": "CreatedDate", "supports_incremental": true, "primary_key": ["Id"], "default_sync_mode": "incremental" } ] }
FieldDescription
cursor_fieldThe column incremental reads track. Absent for a stream read in full every run
supports_incrementalWhether the stream can be read incrementally
primary_keyThe columns that identify a row, used by incremental_merge unless primary_keys overrides them
default_sync_modeThe connector’s recommended sync mode for the stream, applied when a loader is created without stream_sync_modes. Absent when the connector has no recommendation (the stream then follows sync_mode)

List Loader Types

GET /api/v1/loader-types

Returns the list of available loader connector types with their configuration schemas and available streams. This endpoint is global and does not require the X-Workspace-ID header.


Loader Object

FieldTypeDescription
idstring (UUID)Unique identifier
workspace_idstring (UUID)Owning workspace
source_idstring (UUID)Target warehouse source
namestringDisplay name
loader_typestringConnector type
configobjectConnection configuration
target_schemastringWarehouse schema to write to
selected_streamsarray of stringNames of the streams the loader reads
sync_modestringLoader-wide default sync mode: full_refresh, incremental or incremental_merge
stream_sync_modesobjectStream name → sync mode for streams that do not follow sync_mode. Always an object; {} when every stream follows sync_mode
primary_keysobjectStream name → merge-key columns overriding the connector’s key. Always an object
change_detectionobjectStream name → change-detection settings. Always an object
schedulestringCron expression
statusstringdraft, active, paused, or error
status_errorstringError message when status is error
created_bystring (UUID)Account that created the loader
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp
last_run_atstring (ISO 8601) or nullLast run time
last_run_idstring (UUID) or nullID of the most recent run
last_run_statusstringHow the most recent run ended (list responses only)
last_run_errorstringThe most recent run’s error, if it failed (list responses only)

Loader Run Object

FieldTypeDescription
idstring (UUID)Unique identifier
loader_idstring (UUID)Parent loader
workspace_idstring (UUID)Owning workspace
statusstringpending, running, completed, failed, or cancelled
started_atstring (ISO 8601)Run start time
completed_atstring (ISO 8601) or nullRun completion time
rows_loadedintegerTotal rows loaded
streams_totalintegerTotal streams processed
streams_failedintegerNumber of failed streams
error_messagestringError details (if failed)
triggered_bystring (UUID) or nullAccount that triggered the run
job_idstring or nullExternal job identifier
created_atstring (ISO 8601)Record creation time
Last updated on