Skip to main content
These endpoints control reverse ETL: querying your warehouse or lakehouse and writing rows into SaaS tools, ads platforms, and custom HTTP destinations. Authenticate with a Bearer API key. Base URL: https://api.planasonix.com
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
If your workspace uses a versioned base path (for example /v1), prepend it before /api. See API reference.

List syncs

Returns all reverse ETL sync definitions. GET /api/reverse-etl/syncs

Request parameters

destination_id
string
Filter syncs targeting a given destination connection.
enabled
boolean
Filter by active/paused syncs.
limit
integer
default:"50"
Page size.
cursor
string
Pagination cursor.

Example response

{
  "data": [
    {
      "id": "retl_sync_01j9k6m7n8o9p0q1",
      "type": "reverse_etl_sync",
      "attributes": {
        "name": "crm_accounts_warehouse_to_salesforce",
        "destination_id": "conn_sf_prod",
        "object_name": "Account",
        "sync_mode": "upsert",
        "enabled": true,
        "schedule": {
          "type": "cron",
          "expression": "15 */4 * * *",
          "timezone": "UTC"
        },
        "updated_at": "2025-03-26T09:00:00Z"
      }
    }
  ],
  "meta": {
    "page": { "limit": 50, "cursor": null }
  }
}

Create sync

Creates a new sync from a SQL or semantic query to a destination object. POST /api/reverse-etl/syncs

Request body

name
string
required
Display name for the sync.
sourceQuery
string
required
Warehouse query (SQL) or documented semantic reference that resolves to a row set.
destinationId
string
required
Connection ID for the destination (Salesforce, HubSpot, Iterable, and so on).
objectName
string
required
Destination object or resource name (API name for CRM entities, stream name for events APIs).
fieldMappings
array
required
Array of mapping objects: source column or expression → destination field (see example).
syncMode
string
required
One of upsert, insert, update, delete, or connector-specific modes.
schedule
object
Optional schedule: for example { "type": "cron", "expression": "0 * * * *", "timezone": "UTC" } or { "type": "manual" }.

Example response

{
  "data": {
    "id": "retl_sync_01j9k6m7n8o9p0q1",
    "type": "reverse_etl_sync",
    "attributes": {
      "name": "crm_accounts_warehouse_to_salesforce",
      "source_query": "SELECT account_id, name, annual_revenue, last_activity_at FROM analytics.dim_crm_account WHERE is_active = true",
      "destination_id": "conn_sf_prod",
      "object_name": "Account",
      "field_mappings": [
        { "source": "account_id", "destination": "External_Id__c", "key": true },
        { "source": "name", "destination": "Name" },
        { "source": "annual_revenue", "destination": "AnnualRevenue" },
        { "source": "last_activity_at", "destination": "Last_Activity__c" }
      ],
      "sync_mode": "upsert",
      "enabled": true,
      "schedule": {
        "type": "cron",
        "expression": "15 */4 * * *",
        "timezone": "UTC"
      },
      "created_at": "2025-03-27T17:00:00Z",
      "updated_at": "2025-03-27T17:00:00Z"
    }
  }
}

Get sync

GET /api/reverse-etl/syncs/{id}

Request parameters

id
string
required
Sync ID.

Example response

{
  "data": {
    "id": "retl_sync_01j9k6m7n8o9p0q1",
    "type": "reverse_etl_sync",
    "attributes": {
      "name": "crm_accounts_warehouse_to_salesforce",
      "source_query": "SELECT account_id, name, annual_revenue, last_activity_at FROM analytics.dim_crm_account WHERE is_active = true",
      "destination_id": "conn_sf_prod",
      "object_name": "Account",
      "field_mappings": [
        { "source": "account_id", "destination": "External_Id__c", "key": true },
        { "source": "name", "destination": "Name" }
      ],
      "sync_mode": "upsert",
      "enabled": true,
      "schedule": {
        "type": "cron",
        "expression": "15 */4 * * *",
        "timezone": "UTC"
      },
      "created_at": "2025-03-27T17:00:00Z",
      "updated_at": "2025-03-27T17:00:00Z"
    }
  }
}

Update sync

PUT /api/reverse-etl/syncs/{id}

Request parameters

id
string
required
Sync ID.

Request body

Same fields as create, all optional except where the server requires a full replacement for certain connectors.

Example response

{
  "data": {
    "id": "retl_sync_01j9k6m7n8o9p0q1",
    "type": "reverse_etl_sync",
    "attributes": {
      "name": "crm_accounts_warehouse_to_salesforce",
      "sync_mode": "upsert",
      "enabled": true,
      "schedule": {
        "type": "cron",
        "expression": "0 */2 * * *",
        "timezone": "UTC"
      },
      "updated_at": "2025-03-27T17:15:00Z"
    }
  }
}

Delete sync

DELETE /api/reverse-etl/syncs/{id}

Request parameters

id
string
required
Sync ID.

Example response

{
  "data": {
    "id": "retl_sync_01j9k6m7n8o9p0q1",
    "type": "reverse_etl_sync",
    "attributes": {
      "deleted": true,
      "deleted_at": "2025-03-27T17:20:00Z"
    }
  }
}

Trigger sync run

Starts a run for one or more syncs (batch semantics depend on your deployment). POST /api/reverse-etl/sync/run

Request body

syncId
string
Run a single sync by ID.
syncIds
array
Run multiple syncs in one request.
fullRefresh
boolean
default:"false"
When supported, ignores incremental watermark and reprocesses the full query result set.

Example response

{
  "data": {
    "id": "retl_run_01j9k7p2q3r4s5t6",
    "type": "reverse_etl_run",
    "attributes": {
      "sync_id": "retl_sync_01j9k6m7n8o9p0q1",
      "status": "queued",
      "full_refresh": false,
      "created_at": "2025-03-27T17:22:00Z"
    }
  }
}

Toggle sync

Enables or disables a sync without deleting its definition. POST /api/reverse-etl/sync/toggle

Request body

syncId
string
required
Sync ID.
enabled
boolean
required
Target state.

Example response

{
  "data": {
    "id": "retl_sync_01j9k6m7n8o9p0q1",
    "type": "reverse_etl_sync",
    "attributes": {
      "enabled": false,
      "updated_at": "2025-03-27T17:23:30Z"
    }
  }
}

List destinations

Lists destination connections available for reverse ETL in the workspace. GET /api/reverse-etl/destinations

Request parameters

connector
string
Filter by connector type (for example salesforce, hubspot).

Example response

{
  "data": [
    {
      "id": "conn_sf_prod",
      "type": "reverse_etl_destination",
      "attributes": {
        "name": "Salesforce Production",
        "connector": "salesforce",
        "status": "connected",
        "objects_discoverable": true
      }
    }
  ]
}

List destination objects

Returns objects (entities, streams) you can target for a given destination. GET /api/reverse-etl/objects

Request parameters

destination_id
string
required
Destination connection ID.
Case-insensitive filter on object label or API name.

Example response

{
  "data": [
    {
      "id": "Account",
      "type": "destination_object",
      "attributes": {
        "label": "Account",
        "api_name": "Account",
        "supports_upsert": true,
        "writable": true
      }
    },
    {
      "id": "Contact",
      "type": "destination_object",
      "attributes": {
        "label": "Contact",
        "api_name": "Contact",
        "supports_upsert": true,
        "writable": true
      }
    }
  ]
}

List object fields

Returns fields for a destination object, including types and write constraints. GET /api/reverse-etl/fields

Request parameters

destination_id
string
required
Destination connection ID.
object_name
string
required
Object API name.

Example response

{
  "data": [
    {
      "id": "Name",
      "type": "destination_field",
      "attributes": {
        "label": "Account Name",
        "data_type": "string",
        "required": true,
        "updateable": true,
        "external_id": false
      }
    },
    {
      "id": "External_Id__c",
      "type": "destination_field",
      "attributes": {
        "label": "Warehouse Account Id",
        "data_type": "string",
        "required": false,
        "updateable": true,
        "external_id": true
      }
    }
  ]
}

List sync runs

Returns historical reverse ETL run records across syncs. GET /api/reverse-etl/runs

Request parameters

sync_id
string
Restrict to one sync.
status
string
Filter by run status.
limit
integer
default:"50"
Page size.
cursor
string
Pagination cursor.

Example response

{
  "data": [
    {
      "id": "retl_run_01j9k7p2q3r4s5t6",
      "type": "reverse_etl_run",
      "attributes": {
        "sync_id": "retl_sync_01j9k6m7n8o9p0q1",
        "status": "succeeded",
        "rows_read": 12840,
        "rows_written": 12795,
        "rows_failed": 45,
        "started_at": "2025-03-27T12:15:01Z",
        "finished_at": "2025-03-27T12:18:44Z"
      }
    }
  ],
  "meta": {
    "page": { "limit": 50, "cursor": null }
  }
}

List dead letter queue entries

Returns rows or batches that failed after retries and require manual review. GET /api/reverse-etl/dlq

Request parameters

sync_id
string
Filter by sync.
resolved
boolean
false (default) for open failures; true for history.
limit
integer
default:"50"
Page size.
cursor
string
Pagination cursor.

Example response

{
  "data": [
    {
      "id": "retl_dlq_01j9k8u9v0w1x2y3",
      "type": "reverse_etl_dlq_entry",
      "attributes": {
        "sync_id": "retl_sync_01j9k6m7n8o9p0q1",
        "run_id": "retl_run_01j9k7p2q3r4s5t6",
        "error_code": "DESTINATION_VALIDATION",
        "message": "INVALID_EMAIL: bad format for field Email",
        "record_keys": { "External_Id__c": "acc_88291" },
        "attempts": 5,
        "first_seen_at": "2025-03-27T12:16:10Z",
        "resolved": false
      }
    }
  ],
  "meta": {
    "page": { "limit": 50, "cursor": null }
  }
}

DLQ statistics

Aggregate counts for monitoring and alerting. GET /api/reverse-etl/dlq/stats

Request parameters

sync_id
string
Scope stats to one sync; omit for workspace totals.
since
string
ISO 8601 timestamp; only count entries at or after this time.

Example response

{
  "data": {
    "type": "reverse_etl_dlq_stats",
    "attributes": {
      "open_count": 12,
      "resolved_count": 340,
      "by_error_code": {
        "DESTINATION_VALIDATION": 7,
        "RATE_LIMIT": 3,
        "UNKNOWN": 2
      },
      "computed_at": "2025-03-27T17:30:00Z"
    }
  }
}

Resolve DLQ entries

Marks entries resolved after you fix data or choose to skip them; optional replay may enqueue new writes. POST /api/reverse-etl/dlq/resolve

Request body

entryIds
array
required
DLQ entry IDs to resolve.
resolution
string
required
Short reason code: fixed_upstream, skipped, manual_push, and so on.
replay
boolean
default:"false"
When true and supported, re-attempts the affected records in a new run.

Example response

{
  "data": {
    "type": "reverse_etl_dlq_resolve",
    "attributes": {
      "resolved_ids": ["retl_dlq_01j9k8u9v0w1x2y3"],
      "replay_run_id": null,
      "resolved_at": "2025-03-27T17:35:00Z"
    }
  }
}