Warehouse Sync
Warehouse Sync keeps Sequenzy in step with your data warehouse. You write a SQL query, map its columns, and Sequenzy runs it on a schedule: contacts are created or updated, and events are recorded on your contacts. Each run sends only rows that changed since the last run. Set it up in Settings → Data Warehouse, or with the API, the CLI (sequenzy warehouse) or the MCP server.
1. Create a read-only user
Sequenzy only runsSELECT queries, and on Postgres and Redshift every query runs in a read-only transaction. Still, give it a user that can only read what you want to sync.
- Snowflake
- BigQuery
- Redshift and Postgres
Sequenzy uses key-pair authentication. Generate a key and assign its public half to a new user:Then connect with your account identifier (for example
myorg-myaccount), the user, warehouse, database, and the contents of sequenzy_key.p8.2. Write the query
A sync runs oneSELECT (or WITH ... SELECT) statement. Sequenzy wraps it as a subquery, so any query your warehouse accepts works, including joins and views. The query cannot contain semicolons, even inside strings; use CHR(59) (CODE_POINTS_TO_STRING([59]) on BigQuery) if you need to match one:
3. Map columns
- Subscribers
- Events
Contacts go through the same pipeline as imports, with suppression checks and risk review. For existing contacts, mapped values replace the stored ones, empty values never clear what is already there, and unsubscribed contacts are never resubscribed. Contacts the sync creates join the lists you choose; existing contacts keep their list memberships.Imports run as the person who last saved the sync. If that person leaves the workspace or can no longer edit contacts, runs stop with a message; open the sync and save it to continue as you.
4. Choose how it runs
- Cursor column. Pick a column that grows whenever a row changes, such as
updated_at. Each run then reads only rows at or after the last value it saw, which keeps large tables cheap. Rows with an empty cursor are not read. Without a cursor, every run reads the whole result (up to 2,000,000 rows) and skips unchanged rows. Your warehouse bills each run as it bills any query; on BigQuery, a cursor on a partitioned or clustered column keeps the bytes scanned small. - Schedule. Every 15 minutes, hourly, daily, weekly, or manual only. The first run starts when you create the sync.
- Start automations. Off by default. When on, new contacts can enter sequences that start on contact creation, and events from the last hour can start or advance sequences.
- Double opt-in. Off by default, for warehouses that only hold contacts who already agreed to receive email. When on, new contacts get a confirmation email first.
How runs work
- Only changes are sent. Sequenzy keeps a fingerprint of every row it sent. Unchanged rows are counted as unchanged and skipped. A row is only recorded as sent after the import or event write accepted it. Rows that failed inside Sequenzy are read again on the next run; a row that keeps failing where the last run stopped is skipped with a note so the sync can move on. If an import later loses part of its rows, the next run sends every row again, up to three times a day.
- Long backfills continue on their own. With a cursor, a run stops after 30 minutes and the next one starts right away from where it stopped. Without a cursor, the rest waits for the next scheduled run. More than 2,000,000 rows with the same cursor value stop the sync with an error; use a more precise cursor column.
- Edits apply right away. Pausing, deleting or changing a sync stops a run in progress at its next page of rows; a changed sync then runs again with the new settings.
- Progress. The dashboard,
sequenzy warehouse syncs runsand the API show rows read, synced, unchanged, skipped and failed, sample problems with their row numbers, and the progress of the contact imports each run queued. - Failures retry. When a run fails, for example because of an expired key or a SQL error, the sync shows the reason and retries with backoff. Fix the problem and choose Run now to retry immediately.
- Full resync. Forgets what was sent and the cursor position, then sends every row again. Use it after changing data without touching the cursor column.