# What is Whalesync?

An introduction to our product and mission

### Welcome! We're so glad you're here. 💙

Whalesync is a no-code integration tool that **connects your SaaS apps with your favorite spreadsheet**.

Without any code, you can start controlling your business tools from flexible, easy-to-use spreadsheets like Airtable, Notion, and Google Sheets.

<figure><img src="/files/a1zAUs47cEU9jKi6cc4I" alt=""><figcaption></figcaption></figure>

When your apps are deeply connected to spreadsheets you gain work super powers like the ability to:

* Bulk edit records
* Let anyone on the team make updates without training
* Utilize formulas and AI

These super powers enable powerful use cases like:

* Generate thousands of programmatic SEO pages (Webflow + Airtable)
* Track your sales deals in Notion (HubSpot + Notion)
* Build internal tools (Postgres + Airtable)
* Let investors update deals from a sheet (Affinity + Sheets)

## Whalesync is different from tools like Zapier

Our goal is very specific: create a two-way sync between your spreadsheet and your app.

Workflow automation tools like Zapier solve a different problem: on a trigger, run a series of automations.

For more details on the breakdown, check out: [How is Whalesync different from Zapier?](https://www.whalesync.com/blog/how-is-whalesync-different-from-zapier)

<figure><img src="/files/tKQOVmANohqPi0H3xuH4" alt=""><figcaption></figcaption></figure>

## The best way to discover Whalesync is to try it

{% content-ref url="/pages/YVGqYwQICgpRCEXncYb3" %}
[Quick start](/start-here/quick-start)
{% endcontent-ref %}


# Quick start

Set up your first sync in less than 5 minutes

Seeing data sync instantly across your tools is exhilarating. With Whalesync, you can connect apps and start two-way syncing in under five minutes. Here's how:

## Step 1: Create a new sync

From the dashboard, click "New sync" to kick off the setup flow.

<figure><img src="/files/LP9lrFj0sEBzaMSZ7OMS" alt=""><figcaption></figcaption></figure>

## Step 2: Connect your apps

Choose the apps you want to sync and click "Authorize". For certain apps, you'll need to copy and paste an API key, but for most you can sign-in with OAuth.

<figure><img src="/files/4klX02S42Jh5FPUxAbtj" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you're unsure where to find your API Keys, please visit the specific connector documentation.
{% endhint %}

## Step 3: Map tables

Choose the tables you want to map together for syncing.

<figure><img src="/files/QVxZX27ngX205jh2PnoV" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If your table names match exactly, they will show up as suggested.
{% endhint %}

## Step 4: Map fields

After mapping a table, you can map the specific fields you want to sync and choose the sync direction for each one.

<figure><img src="/files/Yg0YpUX9DXhEpYIJFmL4" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Field names do not have to match, but field *types* do need to be compatible.
{% endhint %}

## Step 5: Activate sync

<figure><img src="/files/fqAMpLNsOuHunan46v5C" alt=""><figcaption></figcaption></figure>

:tada:Woo hoo! That's it. Activate sync and within seconds you should see data begin syncing.

{% hint style="info" %}
After turning sync on, you can check the the [operations page](/features/operations) to see sync updates Whalesync makes and the [issues page](/features/issues) to see any sync errors from your connected apps.
{% endhint %}


# Video tutorials

Whalesync tutorials made by us and automation experts

## By Automation Experts

{% tabs %}
{% tab title="Dan Leeman" %}

### HubSpot + Airtable

{% embed url="<https://www.youtube.com/watch?v=BYzPB-Nc9g4>" %}
{% endtab %}

{% tab title="Connor Finlayson" %}

### Airtable + Webflow

{% embed url="<https://www.youtube.com/watch?v=id_6vHPZk4U>" %}
{% endtab %}

{% tab title="Gareth Pronovost" %}

### Airtable + Airtable

{% embed url="<https://www.youtube.com/watch?v=7ZfIQXCgPSI>" %}

### Airtable + Notion

{% embed url="<https://youtu.be/oxI8dNcTdRc?si=e-u-jmTr2CaCTOlq>" %}
{% endtab %}

{% tab title="Tom Nasr" %}

### Airtable + Notion

{% embed url="<https://www.youtube.com/watch?v=BuoG0A5fRb0>" %}
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Surviving Your 20's" %}

### Airtable + Webflow

{% embed url="<https://www.youtube.com/watch?v=GxH41FlukP0>" %}
{% endtab %}
{% endtabs %}

## By Webflow

{% tabs %}
{% tab title="Programmatic SEO Landing Pages" %}

### Progammatic SEO

{% embed url="<https://www.youtube.com/watch?v=FOoNh_OGlYI>" %}
{% endtab %}

{% tab title="Blog Content Creation" %}

### Blog Content Creation

{% embed url="<https://www.youtube.com/watch?v=XBbWyyLeM60>" %}
{% endtab %}
{% endtabs %}


# Webflow + Airtable

Use Airtable as a CMS for your website - build programmatic SEO pages & more.

<figure><img src="/files/bCR4vRpVDZz8U9qeLAsD" alt="" width="449"><figcaption><p><a href="https://www.whalesync.com/sync/airtable-webflow">https://www.whalesync.com/sync/airtable-webflow</a></p></figcaption></figure>

We have a step-by-step guide to help you launch programmatic SEO pages fast—covering strategy, setup with Airtable + Webflow + Whalesync, and common pitfalls.

{% embed url="<https://www.whalesync.com/blog/programmatic-seo-the-ultimate-guide-in-2025>" %}

{% embed url="<https://www.whalesync.com/sync/airtable-webflow>" %}

### Multi-language sites

Building a localized site? Whalesync syncs each Webflow locale as its own table, so you can manage translated CMS content from Airtable.

{% content-ref url="/pages/Tt3heGwKsYWKzFrK0WCz" %}
[Webflow localization](/connectors/webflow/webflow-localization)
{% endcontent-ref %}


# HubSpot + Notion

View and edit your most important CRM data from within your company wiki.


# Supabase + Airtable

Edit your DB from an easy-to-use spreadsheet - build internal tools without any engineers.

<figure><img src="/files/wK02jHF4ZgCXWRXRHCzD" alt="" width="416"><figcaption><p><a href="https://www.whalesync.com/sync/supabase-airtable">https://www.whalesync.com/sync/supabase-airtable</a></p></figcaption></figure>

{% embed url="<https://www.whalesync.com/sync/supabase-airtable>" %}


# Notion + Google Sheets

Bring Sheets formulas into Notion with a true two-way sync.

<figure><img src="/files/SHBQXhKPiOgVKAVr3fGe" alt="" width="446"><figcaption><p><a href="https://www.whalesync.com/sync/notion-google-sheets">https://www.whalesync.com/sync/notion-google-sheets</a></p></figcaption></figure>

{% embed url="<https://www.whalesync.com/sync/notion-google-sheets>" %}


# Affinity

## Supported Tables

<table><thead><tr><th>Tables</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>People</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Organizations</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Opportunities</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Notes</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Lists</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>


# Authorize Affinity

How to get your Affinity API key

**1) Click "Settings"**

<figure><img src="/files/OYutfx07VGYFGDijjvEh" alt=""><figcaption></figcaption></figure>

**2) Click "API", then copy your API key**

<figure><img src="/files/B2ivALVDoU12qQ9zKSIw" alt=""><figcaption></figcaption></figure>


# Full records vs. shallow records

Understanding what a "shallow record" is in Affinity

Unless you are on Affinity's Enterprise plan, Affinity has significant API limitations which limits our ability to sync all records. To work around this, Whalesync groups your records into two categories:

* Records you care about (full records)
* Records you don't care about (shallow records)

#### Affinity API limits

Affinity has the following API quota limits on its plans:

* Starter = none
* Premium = 100,000 calls/mo
* Enterprise = unlimited

**Difference between full records and shallow records**

Full records include every field you want to sync:

<figure><img src="/files/8T3NJo1XFI3sbVE4cNU0" alt=""><figcaption></figcaption></figure>

Shallow records only include the display name and email address (if applicable):

![](/files/x0FpZQiyQ5kQCQKUm8Ju)

#### How to sync full records

By default, Whalesync will sync records as shallow records. If you want to fully sync a group of records you must:

1. Add them to at least one list
2. Select to fully sync that list on the table mapping screen

<figure><img src="/files/YUSKtPiZxPSViBwVZTsP" alt=""><figcaption><p>Open table settings on the table mapping screen</p></figcaption></figure>

<figure><img src="/files/HmOlcpQAfwIrW0sRwWyH" alt=""><figcaption><p>Add the lists you want to fully sync</p></figcaption></figure>


# List-specific fields

How to sync list-specific fields in Affinity

Affinity lets you add list-specific fields that only appear on specific lists:

<figure><img src="/files/67S7PcpvLjG8MWyYIDCL" alt=""><figcaption><p>Example of adding a list-specific field</p></figcaption></figure>

List-specific fields show up in Whalesync as available fields to map with a prefix of the list like so:

<figure><img src="/files/blH6ocFXrkYDuO6F4IGF" alt=""><figcaption><p>Example of a list-specific Amount field on the "Opp list 2" list</p></figcaption></figure>


# Notes in Affinity

Things to be aware of when syncing Affinity notes

### Creating vs. editing

If you map the "Notes" table and intend to author notes in another tool such as Airtable or Notion, there's a limitation you should be aware of. When creating a brand new note in Affinity, Whalesync is able to set all the note's properties: its contents and which people/organizations/opportunities it's associated with.

However, when editing a note, Whalesync can **only** modify the contents of the note. It cannot change the people/organizations/opportunities it's associated with.

Therefore we recommend setting a long sync delay on the "Notes" table mapping such that Whalesync only creates notes in Affinity once you've had the chance to set the appropriate references.

<figure><img src="/files/EqJmrX7jKfAhXUI7g91B" alt=""><figcaption><p>Edit mapping options for the "Notes" table</p></figcaption></figure>

<figure><img src="/files/mB2AfXWQjy3YCkfKhp9F" alt=""><figcaption><p>Set a long delay on the source of the notes</p></figcaption></figure>

### Notes and rich text

Notes in Affinity are usually stored as rich text. Under the hood, Affinity's internal representation of notes is [Markdown](https://en.wikipedia.org/wiki/Markdown), a simple formatting language. When you create notes within Affinity's UI, Whalesync sees those notes as being formatted in Markdown. You can map the contents of notes to a rich text field in tool such as Airtable and the formatting will correctly be synced.

However, due to a bug in the Affinity API, Whalesync is only able to edit notes in Affinity as plain text. When you create rich text notes in another tool and they're synced to Affinity, they will show up with the raw Markdown formatting like this:

```
Hello World!
This is **bold**, _italic_, ~~strikethrough~~, and `code`.
Here is a [link](https://en.wikipedia.org/wiki/Whale).
```


# Airtable

## Airtable Connector Guide

This guide provides an overview of how to connect Whalesync to Airtable and answers common questions.

### Connecting to Airtable

To connect your Airtable account to Whalesync, you'll need to authenticate using OAuth. This is a secure way to grant Whalesync access to your Airtable data without sharing your password.

When you connect, Airtable will ask you to authorize Whalesync to perform specific actions. Here’s what we ask for and why:

* `data.records:read` and `data.records:write`: Allows Whalesync to read and write records (rows) in your tables to keep them in sync.
* `schema.bases:read` and `schema.bases:write`: Allows Whalesync to understand the structure of your bases, tables, and fields. We also use this to automatically create tables and fields in Airtable if you want us to.
* `data.recordComments:read` and `data.recordComments:write` : Allows Whalesync to read and write comments in records
* `webhook:manage`: Allows Whalesync to set up webhooks, which notify us instantly when data changes in Airtable, enabling real-time syncing.

You will need to grant access to the specific Bases you want to sync with Whalesync.

### Syncing Data

#### Bases and Tables

In Airtable, your data is organized into **Bases**, which are like databases or spreadsheets. Each base contains **Tables**, and tables contain your data in records (rows) and fields (columns). Whalesync uses the same terminology.

#### Syncing Specific Views

One powerful feature of our Airtable connector is the ability to sync a specific **View**. A View in Airtable lets you filter and sort your records. By choosing a view to sync in Whalesync, you can control exactly which records are included in your sync.

For example, you could create a view in Airtable called "Ready to Publish" that only shows records where a "Status" field is set to "Published". By syncing this view, you ensure only those specific records are synced by Whalesync.

If you don't select a view, Whalesync will sync **all records** in the table.

Note - you can't use Airtable view sync and two-way sync at the same time. See below for details:

{% content-ref url="/pages/UGVsRab2lRYeRViLjDmV" %}
[Airtable view sync](/connectors/airtable/airtable-view-sync)
{% endcontent-ref %}

#### Automatic Table and Field Creation

Whalesync can automatically create tables and fields in Airtable to match the structure of the other app you're syncing with.

### Important Considerations

#### API Quotas

Airtable has API request limits, especially on their Free and Team plans. If you have a large number of records or your data changes very frequently, you might hit these limits. We recommend considering Airtable's Business or Enterprise plans for heavy usage to avoid sync interruptions.

#### Attachments

Please be aware that when syncing attachment fields, the file names of your attachments may change.

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🤖 AI field</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 Attachment (Image)</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Autonumber</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📇 Barcode</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔘 Button</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>☑️ Checkbox</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🫂 Collaborator</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔢 Count</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🧑 Created by</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>💱 Currency</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📅 Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>⏱️ Duration</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>✉️ Email</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📊 Formula</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🖇️ Linked records</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Linked records - multiple</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Long text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📰 Long text - rich text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>👀 Lookup</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🏷️ Multi-select</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>➗ Percent</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📞 Phone number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>⭐ Rating</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🆔 Record ID</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🌀 Rollup</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔽 Single select</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Single line text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔗 URL</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>

### Synthetic Fields

Whalesync adds some special fields to your Airtable tables. These fields are not visible in Airtable but are available to map in your sync.

| Field Name            | Explanation                                             | Writable |
| --------------------- | ------------------------------------------------------- | -------- |
| Airtable Record ID    | The unique identifier for a record in Airtable.         | No       |
| Airtable Created Time | The timestamp of when a record was created in Airtable. | No       |

###


# Airtable view sync

Sync specific views in Airtable

<figure><img src="/files/6dyjH3Qj0SvRJVtHCVow" alt=""><figcaption><p>Choosing to map an Airtable view instead of the entire table</p></figcaption></figure>

### About Airtable view sync

[Airtable views](https://support.airtable.com/hc/en-us/articles/202624989-Views-overview) are filtered subsets of the data in Airtable.

With Airtable view sync, you can sync specific views instead of the entire table.

### How to use Airtable view sync

When mapping tables, choose the Airtable view you'd like to sync instead of the entire table.

<figure><img src="/files/H3BofpOn2CRYKDlGbRxP" alt=""><figcaption></figcaption></figure>

### Limitations

{% hint style="danger" %}
**If you change your Airtable view, updates will not sync until the next "full sync"**\
Airtable doesn't alert Whalesync if you change your Airtable view configuration, so Whalesync won't sync these changes until the next time it does a "full sync".
{% endhint %}

<figure><img src="/files/QuXFzpSGztqnVpbkj6xZ" alt=""><figcaption><p>After changing a filter like this, updates will not sync until the next "full sync"</p></figcaption></figure>


# Airtable API quota

Airtable has strict API quota limits on its two lowest plans:

* Airtable's **Free plan**: 1,000 calls per workspace per month
* Airtable's **Team plan**: 100,000 calls per workspace per month
* Airtable's **Business and Enterprise plans** have unlimited API quota

In order to accomplish fast two-way sync, Whalesync can use a significant number of API calls each month. The number of API calls can depend on several factors: the number of syncs you have for a workspace, the number of records you have in your bases, and the number of edits that Whalesync needs to sync.

For this reason, we highly recommend subscribing to **Airtable Business or Enterprise** when using Whalesync. The Airtable Free plan will almost certainly run out of quota and the Airtable Team plan may or may not have enough quota depending on your syncing needs.

You can learn more about Airtable's API limits in their [API docs](https://support.airtable.com/docs/getting-started-with-airtables-web-api) and on their [pricing page](https://airtable.com/pricing).


# Attio

You can use Whalesync to create a 2-way sync between Attio and Airtable, Google Sheets, Notion, and many more connectors!

## Supported Tables

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported yet" color="blue"></option><option value="IWkvGke3mje6" label="✖️  Coming Soon!" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>👥 People</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🏢 Companies</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4b0">💰</span> Deals</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👤 Workspace Members</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>☑️ Tasks</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported yet</span></td><td></td></tr><tr><td>📝 Notes</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported yet</span></td><td></td></tr><tr><td>🧩 Custom Objects</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>📋 Lists</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr></tbody></table>

## Supported Fields

<table><thead><tr><th>Field Types</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported yet" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f194">🆔</span> Record ID</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f524">🔤</span> Name</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c4">📄</span>Text Fields</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c5">📅</span> Dates</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f517">🔗</span> Domains and Social Media</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4e7">📧</span> Email</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4de">📞</span> Phone Number</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4b2">💲</span> Currency</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="2b05">⬅️</span> Relationship Fields (Team, Company)</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4aa">💪</span> Connection Strength</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4cf">📏</span> Custom Attributes: Text, Date, Rating</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4d0">📐</span> Custom Attributes: Number, Checkbox, Single-select, Multi-select</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f6d1">🛑</span> Custom Attributes: Records, Location, Phone Number, Status, Relationship</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported yet</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4d1">📑</span> Tabs</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported yet</span></td><td></td></tr><tr><td>📋 List Attributes</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported yet</span></td><td></td></tr></tbody></table>

{% hint style="danger" %}
Some fields in Attio don’t support webhooks, which may result in delays when syncing these fields. (e.g. Custom Attributes: Single select and Multi-select fields)
{% endhint %}

### How to Use

{% embed url="<https://youtu.be/jUTvu0d7OUw>" %}

### Using Relationship Fields when syncing Attio with Google Sheets

For more details about how to use Relationship Fields (Foreign Keys) with Google Sheets:

{% content-ref url="/pages/u0GKTqMWSAgrqIAsIh6J" %}
[Foreign keys](/connectors/google-sheets/foreign-keys)
{% endcontent-ref %}


# Attio lists

Sync Attio lists as their own tables in Whalesync

### About Attio lists

[Attio lists](https://attio.com/help/reference/attio-101/attios-data-model/understanding-lists) let you organize a curated set of records — like the companies in your current fundraising pipeline or the people attending an event. Each entry in a list points at a record from the list's parent object (for example, a Company or a Person), and lists can have their own attributes such as a status or a rating that only exist on the list.

With Whalesync, each of your Attio lists shows up as its own table that you can map and sync, just like People or Companies.

### How to sync a list

When mapping tables, your lists appear alongside the standard Attio tables (People, Companies, Deals, etc.). Choose the list you'd like to sync and map its fields like any other table.

Each row in a list table is one **list entry**, and its fields come from three places:

1. **List attributes** — the fields that belong to the list itself (like a pipeline stage or rating). These sync normally, in both directions.
2. **The Parent Record field** — which record this entry points at (see below).
3. **The parent record's fields** — the fields of the Company, Person, or other record the entry points at, included on the row as **read-only** columns.

### The Parent Record field

Every list entry belongs to exactly one record in the list's parent object. Whalesync exposes this as a **Parent Record** field containing that record's Attio record ID.

A few things to know about this field:

* **It's required when creating an entry.** To add a new entry to a list through Whalesync, the Parent Record field must contain the Attio record ID of the record you want to add. If it's empty, the entry can't be created and Whalesync will show a sync error for that row.
* **It can't be changed after creation.** Attio doesn't allow an entry to be re-pointed at a different record. If you change the value in your other app, Whalesync won't push the change, and the field will revert to the true parent on the next sync.
* **It's a plain text field, not a linked record.** This is intentional — see the next section.

### Syncing a list without its parent table

Because the Parent Record field is a plain ID field rather than a linked record (foreign key), **you can sync a list all by itself** — you don't need to also add the People or Companies table to your sync just to make the list work.

You still get the parent record's data, though: Whalesync merges the parent object's fields into each list entry as read-only columns. So a "Fundraising pipeline" list of companies will show each company's name, domains, and other fields right on the list row, even if the Companies table isn't part of your sync.

{% hint style="info" %}
**Want to edit the parent record's fields too?** The parent fields on a list row are read-only. To make changes to the companies or people themselves, add the parent table (e.g. Companies) to your sync and edit the fields there.
{% endhint %}

### Things to keep in mind

{% hint style="info" %}
**Deleting a list entry doesn't delete the record.** If a row is deleted from a synced list table, Whalesync removes the entry from the list in Attio — the underlying company or person record is not touched.
{% endhint %}

{% hint style="warning" %}
**Parent record fields may lag slightly if the parent table isn't synced.** When you sync a list by itself, changes to the entries themselves sync in real time, but edits made directly to a parent record (like renaming a company) are picked up on the next scheduled polling round rather than instantly. Syncing the parent table alongside the list keeps those fields up to date in real time.
{% endhint %}

{% hint style="warning" %}
**Field name overlaps favor the list.** Both the list entry and its parent record have fields like "Created at" and "Created by". When names overlap, the column on the list table refers to the **entry** (e.g. when the record was added to the list), not the parent record.
{% endhint %}

### Limitations

* **Lists with multiple parent objects are read-only.** Almost all lists have a single parent object, but if a list accepts entries from more than one object type, Whalesync can sync it one-way (out of Attio) only.
* **Deleting a list breaks its table.** Lists are matched by their internal ID, so renaming a list in Attio is fine — the sync keeps working. But if a list is deleted in Attio, its table will show an error in Whalesync and you'll need to remove it from your mapping.


# Attio custom objects

Sync your Attio custom objects just like People and Companies

### About custom objects

[Custom objects](https://attio.com/help/reference/managing-your-data/objects/create-and-manage-custom-objects) let you track things in Attio beyond the built-in objects — think Projects, Invoices, Properties, or anything else specific to your business.

Whalesync syncs custom objects exactly like the standard Attio objects (People, Companies, Deals). Anything you can do with a built-in object, you can do with a custom one.

### How to sync a custom object

When mapping tables, your custom objects appear in the dropdown list of tables alongside the standard Attio tables. Choose the custom object you'd like to sync and map its fields like any other table.

### Foreign keys

Custom objects fully support reference fields (foreign keys), in both directions:

* Other tables can reference your custom object — for example, a Deals table with a link to your custom "Properties" object.
* Your custom object can reference other tables — for example, a custom "Invoices" object with a link to Companies.

For more on how reference fields work across apps, see :point\_down:

{% content-ref url="/pages/ocVKxSMliPmoS7zWH2J6" %}
[Reference fields](/features/additional-features/reference-fields)
{% endcontent-ref %}

### Syncing via a list

Custom objects also work with [Attio lists](/connectors/attio/attio-lists). If you have a list whose parent object is a custom object — say, a "Renewals pipeline" list of your custom "Contracts" records — you can sync that list just like a list of Companies or People, including creating new entries from your other app.

### Things to keep in mind

{% hint style="warning" %}
**Record labels come from the "name" attribute.** Whalesync uses an attribute called "name", if present, to label records in the UI. If your custom object doesn't have a "name" attribute, records will be labeled with their unique identifier instead. This only affects how records are displayed in Whalesync — your data syncs the same either way.
{% endhint %}


# Google Sheets

## Google Sheets Connector Guide

This guide provides an overview of how to connect Whalesync to Google Sheets and answers common questions.

### Connecting to Google Sheets

To connect Whalesync to Google Sheets, you will need to authenticate your Google account. Whalesync uses OAuth, a secure standard that allows you to grant access to your Google Sheets without sharing your password.

When you set up Google Sheets in Whalesync, you will be prompted to:

1. Provide the URL of your sheet
2. Sign in to your Google account.
3. Grant Whalesync permission to access your spreadsheets. This permission allows Whalesync to read and write data according to your sync configuration.

Once authenticated, you can select the specific spreadsheet you want to sync.

### Syncing Data

**Sheets (tabs)**

Whalesync uses the name of a sheet (i.e. a tab in a workbook) for syncing. Avoid changing the name of a sheet after setting up your sync, as this will break the sync configuration.

**Rows**

Whalesync uses the first row to define the fields for syncing. By default, Whalesync freezes the first row to preserve this mapping.

Don't delete or move the first row. Altering it will cause sync problems because Whalesync uses it to map your data. After the initial sync, you're free to reorder rows or columns—just keep the first row unchanged.

**Columns**

Whalesync adds a "Whalesync ID" column to your sheet to enable syncing. This column is automatically created in column A and is used to track records.

You are free to rename other columns after setting up a sync. Avoid editing the "Whalesync ID" column to prevent sync errors.

### Formatting Special Fields in Google Sheets

To use special field types like relations (linked records), multi-select dropdowns, or checkboxes, you format the column headers in your Google Sheet in a specific way. Whalesync detects these formats and configures the fields accordingly.

* **Relation (Linked Record) Fields**: To link records to another table (sheet), name your column header using the format `Related_TableName`. For example, in a "Tasks" sheet, to create a field that links to a sheet named "Users", the column header should be `Related_Users`. The table name in the header must exactly match the name of the sheet you are linking to, including capitalization, as described in the [foreign keys documentation](https://docs.whalesync.com/connectors/google-sheets/foreign-keys).
* **Multi-Select Fields**: To create a multi-select field, prefix the column name with `multi_`. For example, a column named `multi_Tags` will be treated as a multi-select field. [Read more about multi-select fields here](/connectors/google-sheets/multi-select-fields).
* **Checkbox (Boolean) Fields**: To create a checkbox field, prefix the column name with `boolean_`. For example, a column named `boolean_Is Active` will be treated as a checkbox that stores TRUE/FALSE values.
* **Other Field Types:** See [the page on formatting columns and field types](/connectors/google-sheets/formatting-columns) for more information on how to ensure your columns are set up correctly.

### Things to Keep in Mind

⚠️ Before syncing Google Sheets some things to note before turning on syncing.

**Do not use the "Sort range" feature on sheets that are syncing!** This action will cause sync problems as it can change the internal row IDs that Whalesync relies on.

Whalesync uses the first row of Google Sheets for sync mapping. Do not delete or move it to avoid issues.

{% hint style="warning" %}
When syncing with Google Sheets, ensure that the Sheet you’re connecting isn’t already used in another sync. Setting up multiple syncs using the same Sheet can lead to conflicts and issues in syncing.
{% endhint %}

### Synthetic Fields

Whalesync adds special read-only fields to your tables that contain metadata about the sync. These fields provide useful information but are managed by Whalesync and cannot be edited.

| Field Name              | Explanation                                                                                                                        | Writable |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------- |
| Google Sheets Record ID | A unique identifier Whalesync uses to track each row. This column is located in column A of your sheet and labeled "Whalesync ID". | No       |

### Supported Fields

| Field         | Status               |
| ------------- | -------------------- |
| 📝Text        | ✅ Supported          |
| 🔢 Number     | ✅ Supported          |
| 📅 Date       | ✅ Supported          |
| #️⃣Percentage | ✅ Supported          |
| 💰 Currency   | ✅ Supported          |
| 📧 Email      | ✅ Supported          |
| 📜 Drop-Down  | ✅ Supported          |
| 🗳️ Checkbox  | ➡️ Supported (1-Way) |
| Relation      | ✅ Supported          |

## Video Guide <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

{% embed url="<https://youtu.be/ledVk0ck-Vc>" %}
A quick video demo for how to sync Google Sheets and Airtable
{% endembed %}


# Formatting columns

Quick guide on how to format columns (i.e. data types) in Google Sheets

### About data types

Google Sheets has two data type categories: 1) Numbers and 2) Text

<figure><img src="/files/dQwlYanmA3HPNsPx7z0O" alt="" width="486"><figcaption></figcaption></figure>

### How to Format columns

To format a column in Google Sheets simply:

1. Highlight the column
2. Select "Format"
3. Choose the data type

<figure><img src="/files/FUUYoBLxQgcjwWAXigZ1" alt=""><figcaption><p>Example formatting a column to the Date data type</p></figcaption></figure>

### Why formatting columns is important

In order to two-way sync fields, data types must match across your apps.

For example, if you have a `Date` field in Airtable and want to two-way sync it with Google Sheets, you'll need a `Date` field in Google Sheets.

### Data types in Google Sheets

#### Text

Text fields will two-way sync by default. No additional formatting is needed for:

* Text
* Long-text
* Drop-down
* Multiple Select
* Email

#### Numbers

Number fields need to be formatted in order to two-way sync:

1. Numbers
2. Percentages
3. Dates

#### Bonus: foreign keys

Learn how to use foreign keys in Google Sheets here:

{% content-ref url="/pages/u0GKTqMWSAgrqIAsIh6J" %}
[Foreign keys](/connectors/google-sheets/foreign-keys)
{% endcontent-ref %}


# Foreign keys

An explanation of how to set up foreign key (aka reference) field relationships in Sheets

Foreign keys allow you to create relationships between tables in your synced Google Sheets.

<figure><img src="/files/Yd6Cn3SwButID1XTeZHB" alt=""><figcaption><p>An example of a foreign key field relating People to Tasks</p></figcaption></figure>

### How to set up foreign keys

#### 1. Define a foreign key column

Create a column in the following format: `Related_[Table Name]`

<figure><img src="/files/fbwhjHCaQdnSescvFVSc" alt=""><figcaption><p>Here our column name is "Related_People" because we're relating Tasks to the People table</p></figcaption></figure>

{% hint style="info" %}
Capitalization matters, so make sure the table name matches exactly.
{% endhint %}

#### 2. Map the Foreign Key field in Whalesync

<figure><img src="/files/ekApGVxMMhZIRwyBavjY" alt=""><figcaption></figcaption></figure>

Google Sheets foreign key fields map with [reference fields](/features/additional-features/reference-fields) in other apps.

{% hint style="info" %}
You will likely need to click "Referesh" to ensure Whalesync sees your newest fields
{% endhint %}

#### 3. Insert Foreign Key values

To link a row from another table to your Foreign Key column:

1. Copy the Whalesync ID of the row you want to reference.
2. Paste the Whalesync ID into the foreign key column.

<figure><img src="/files/qqle3QSvKCZ2gaYoBOQ4" alt=""><figcaption><p>Copying the Whalesync ID from a person in the People's table into the "Related_People" column in Tasks</p></figcaption></figure>

* The Whalesync ID is a unique identifier for each row.
* It is Column A in each mapped table in Google Sheets, and it is hidden.
* Click on the arrow to unhide the Whalesync ID column.

{% hint style="warning" %}
**Avoid making any changes to the Whalesync ID column to avoid sync issues.**
{% endhint %}


# Multi-select fields

An explanation of how to set up multi-select fields in Google Sheets

You can now use Whalesync to sync multi-select fields in Google Sheets. Multi-select allows you to store multiple values in a single cell, such as tags, categories, or any other list of options.

### How to Set Up Multi-Select in Google Sheets

**Step 1:** Label the multi-select column

* Rename the column in your Google Sheet using the format: `multi_[column name]`.\
  \&#xNAN;*Example: If you're tracking tags, name the column `multi_Tags`.*
* A multi-select "Frequented Cities" column is shown below.

<figure><img src="/files/ciI8hfyUWFvMLzhLVQ1S" alt=""><figcaption><p>Shows a multi-select field</p></figcaption></figure>

**Step 2 (optional):** Set the column as multi-select in Google Sheets

* In Google Sheets, navigate to **Data → Data Validation**.
* Set the column's data validation to allow multi-select.

<figure><img src="/files/ymmCbHqjwZR01cuVMOMx" alt="" width="346"><figcaption><p>Shows how to find the Data Validation menu</p></figcaption></figure>

**Step 3 (optional):** Add selectable options in the field

* Enter all the options you want to include in the multi-select field.
* Check the "Allow multiple selections" box if you want the field to be multi-select.
  * If the box is unchecked, the field will become a single-select field.
* *Tip: Highlight all the rows you want affected in the field **except** for the header (as shown below).*

<figure><img src="/files/0WT0R2FKJYZJIAGV7cE4" alt="" width="159"><figcaption><p>Shows selection criteria</p></figcaption></figure>

**Step 4:** Map the Table and Sync

* Complete the table mapping in Whalesync, then activate your sync.
* Multi-select fields will appear as shown below.

<figure><img src="/files/J3eH8rpDCDh7uIgY0PxE" alt=""><figcaption><p>Shows how Google Sheets multi-select fields appear in Table Mapping</p></figcaption></figure>


# Avoid sort range

Sheet's "sort range" feature will cause sync problems

<figure><img src="/files/3tBBAAVh62YEGIibDvU2" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Avoid using "sort range" on Sheets that are syncing.
{% endhint %}

#### Why to avoid sort range?

* To sync your data, Whalesync needs an "ID" for each of your records.
* Google Sheets doesn't have a concept of "record IDs", so Whalesync adds one with a `Whalesync ID` column
* Using "Sort range" can lead to scrambling all the Whalesync IDs in your rows if the Whalesync ID column is not included in the sort.
* This which will lead to unintended changes to your data.

**How to use sort range safely**

* If you must use sort range, be sure to include the Whalesync ID column in your sort range to avoid unintended changes.


# Whalesync ID column

Why Whalesync adds a "Whalesync ID" column to your sheets

To enable syncing, Whalesync adds a “Whalesync ID” column to each sheet in your Google Sheets.

<figure><img src="/files/IjbzHNGBGa5Lu5oKxYG6" alt="" width="563"><figcaption><p>Example Whalesync ID column</p></figcaption></figure>

#### Why does Whalesync need to add a Whalesync ID column?

Unlike most apps and databases, Google Sheets doesn’t assign a unique ID to each row. To enable syncing, Whalesync adds its own ID column to uniquely identify each row.

#### Can I edit this column?

In general, you want to avoid editing this column since it is how Whalesync identifies each row. For example, this is why we suggest [avoiding sort range](/connectors/google-sheets/avoid-sort-range).


# HubSpot

## Supported Objects

<table><thead><tr><th>Objects</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>📞 Calls</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>👥 Contact</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🏢 Companies</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📡 Communications</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>⚙️ Custom Objects</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🤝 Deals</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📧 Emails</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🧾 Line Items</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🤝 Meetings</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Notes</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📦 Products</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c3">📃</span> Quotes</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span> Tasks</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🏦 Taxes</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🎫 Tickets</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🧑‍🔧 Services</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>

## Things to Keep in Mind

### Backup Service

{% hint style="warning" %}
**If two-way syncing HubSpot, we recommend using a backup service.**
{% endhint %}

HubSpot does not have built-in backup/restore functionality. Two-way sync is very powerful. A consequence is a mistake in a connected app could impact all of your HubSpot data at once.

As a precaution, we suggest using a HubSpot backup solution such as:

* [SysCloud Backup](https://ecosystem.hubspot.com/marketplace/apps/syscloud-backup-for-hubspot-595013)
* [Pro Backup](https://ecosystem.hubspot.com/marketplace/apps/pro-backup-380854)

### Associations

See guide below on how to sync Association fields.

{% content-ref url="/pages/1YkCHyORSCX8s7PmqOEm" %}
[Associations](/connectors/hubspot/associations)
{% endcontent-ref %}

### Properties with supported webhooks

See guide below on which HubSpot properties have webhooks supported.

{% content-ref url="/pages/HDUzEuKPRgw9UzqToym8" %}
[Webhooks](/connectors/hubspot/webhooks)
{% endcontent-ref %}

## Video Guide

{% embed url="<https://www.youtube.com/watch?v=y-pfnZiQkZY>" %}

## Setup Guide

Whalesync integrates HubSpot with other apps like Airtable and Salesforce. This enables you to do things like:

* Manage your HubSpot Contacts from an internal Airtable app
* Sync all HubSpot Deals to Salesforce continuously

### Install

1. Create a new base

   <figure><img src="/files/cS9GryzTaewmZZAFkt0R" alt=""><figcaption></figcaption></figure>
2. Choose HubSpot and click 'Authorize'

   <figure><img src="/files/RCYckuj3iRXIgv58A5CA" alt=""><figcaption></figcaption></figure>
3. Choose your HubSpot account

   <figure><img src="/files/uqBQPZylsfYWtpQfQ4jL" alt=""><figcaption></figcaption></figure>
4. Choose your connected app (e.g. Airtable, Notion, Salesforce, etc.) and authorize

   <figure><img src="/files/IACUPw4M9nXZqayWqVW3" alt=""><figcaption></figcaption></figure>

### Configure

5. Map the tables (aka Objects) you want to sync between HubSpot and your connected app and click 'Map Fields'

   <figure><img src="/files/m2Qzg3XPcU5JuDqfmpkm" alt=""><figcaption></figcaption></figure>
6. Map the fields you want to sync between HubSpot and your connected app and click 'Save Base'

   <figure><img src="/files/RACi2AwDnS1IgWgYto1H" alt=""><figcaption></figcaption></figure>

### Use

7. Toggle sync on to begin syncing

   <figure><img src="/files/N9dGUFCpazKBVeF0Ht1X" alt=""><figcaption></figcaption></figure>

### Disconnect

8. To turn sync off, toggle sync off

   <figure><img src="/files/KcqJW8zU6MiWVk1afHwS" alt=""><figcaption></figcaption></figure>
9. To delete your base, click the settings button and then 'Delete'

   <figure><img src="/files/hAsr8MFNBkKJEduQxSmo" alt=""><figcaption></figcaption></figure>


# Associations

How to sync HubSpot associations with Whalesync

#### TL;DR

* Whalesync supports two-way syncing HubSpot associations :tada:
* In order to two-way sync associations, you'll need to map the field correctly
* You can map associations with foreign keys (i.e. linked records)

#### **Compatible Fields**

Each app calls it something slightly different, but here are the fields that are compatible with HubSpot associations.

| App      | Name          |
| -------- | ------------- |
| HubSpot  | Association   |
| Postgres | Foreign Key   |
| Airtable | Linked Record |
| Notion   | Relation      |
| Webflow  | Reference     |

For a more detailed explanation of how these types of fields work, see :point\_down:

{% content-ref url="/pages/ocVKxSMliPmoS7zWH2J6" %}
[Reference fields](/features/additional-features/reference-fields)
{% endcontent-ref %}

#### **Caveats**

{% hint style="warning" %}
For now, Whalesync is not able to sync associations for custom objects.
{% endhint %}


# Webhooks

Info on which properties HubSpot supports webhooks for and how that impacts syncing

## FAQ

### When does Whalesync use webhooks?

* Whalesync uses webhooks whenever possible to offer instant syncing.
* HubSpot supports webhooks for many of its properties but not *all* of them.

### What happens when HubSpot doesn't offer webhooks?

* Whalesync relies on polling to detect changes when HubSpot doesn't offer webhooks.
* Polling happens once every 3 hours.

### All together, how fast will Whalesync sync changes in HubSpot?

* Changes in any of the webhook-supported properties below will be detected within seconds.
* Changes in properties HubSpot does not offer webhooks for will be detected once every 3 hours.

## Properties with Webhooks

Below is a list of properties for which HubSpot supports webhooks:

{% tabs %}
{% tab title="Contacts" %}

```
firstname 
lastname 
email 
mobilephone 
address 
zip 
message 
website 
twitterhandle 
hs_analytics_source 
hs_persona 
followercount 
industry 
annualrevenue 
numemployees 
lifecyclestage 
closedate 
company 
jobtitle 
hs_language 
country 
city 
fax 
state 
twitterprofilephoto 
hs_legal_basis 
salutation 
phone 
hs_content_membership_notes 
hs_content_membership_status 
hs_buying_role 
hs_lead_status 
hubspot_owner_id 
owneremail 
ownername 
hs_all_assigned_business_unit_ids 
hs_content_membership_email 
hs_country_region_code 
hs_journey_stage 
hs_role 
hs_seniority 
hs_shared_team_ids 
hs_shared_user_ids 
hs_state_code 
hs_sub_role 
hs_time_between_contact_creation_and_deal_close 
hs_time_between_contact_creation_and_deal_creation 
hs_time_to_move_from_lead_to_customer 
hs_time_to_move_from_marketingqualifiedlead_to_customer 
hs_time_to_move_from_opportunity_to_customer 
hs_time_to_move_from_salesqualifiedlead_to_customer 
hs_time_to_move_from_subscriber_to_customer 
hs_timezone 
hs_whatsapp_phone_number 
hs_linkedin_url 
linkedinbio 
linkedinconnections 
twitterbio 
hs_latest_source 
hs_latest_source_timestamp 
hs_facebook_click_id 
hs_google_click_id 
hs_email_customer_quarantined_reason 
company_size 
date_of_birth 
degree 
field_of_study 
gender 
graduation_date 
job_function 
marital_status 
military_status 
relationship_status 
school 
seniority 
start_date 
kloutscoregeneral 
work_email 
```

{% endtab %}

{% tab title="Companies" %}

```
name 
phone 
city 
zip 
numberofemployees 
lifecyclestage 
description 
web_technologies 
twitterfollowers 
linkedinbio 
hs_analytics_source 
facebookfans 
timezone 
founded_year 
linkedin_company_page 
facebook_company_page 
twitterbio 
twitterhandle 
type 
hs_lead_status 
annualrevenue 
closedate 
industry 
domain 
website 
country 
state 
address2 
googleplus_page 
about_us 
address 
total_money_raised 
hubspot_owner_id 
hs_all_assigned_business_unit_ids 
hs_country_code 
hs_csm_sentiment 
hs_employee_range 
hs_industry_group 
hs_keywords 
hs_linkedin_handle 
hs_logo_url 
hs_quick_context 
hs_revenue_range 
hs_shared_team_ids 
hs_shared_user_ids 
owneremail 
ownername 
hs_ideal_customer_profile
```

{% endtab %}

{% tab title="Deals" %}

```
dealname 
amount 
closedate 
dealtype 
closed_lost_reason 
closed_won_reason 
description 
createdate 
deal_currency_code 
hs_analytics_source 
dealstage 
pipeline 
hs_exchange_rate 
ecosystem_trx_refunded_at 
hs_all_assigned_business_unit_ids 
hs_deal_stage_probability 
hs_forecast_probability 
hs_manual_forecast_category 
hs_next_step 
hs_priority 
hs_shared_team_ids 
hs_shared_user_ids 
hubspot_owner_id 
```

{% endtab %}

{% tab title="Tickets" %}

```

subject changed
content changed
source_type changed
hs_resolution changed
createdate changed
hs_ticket_priority changed
hs_pipeline changed
hs_pipeline_stage changed
hs_ticket_category changed
closed_date changed
hs_file_upload changed
hs_last_closed_date changed
hs_all_assigned_business_unit_ids changed
hs_shared_team_ids changed
hs_shared_user_ids changed
hs_time_to_close_in_operating_hours changed
hs_time_to_first_response_in_operating_hours changed
hubspot_owner_id changed
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Webhooks are **not** supported for *custom properties*. You can sync custom properties with Whalesync, but changes will only be detected during polling.
{% endhint %}


# Merging records

Merging records in HubSpot will cause records to be deleted in your synced spreadsheet

In HubSpot, you have the ability to merge duplicate records.

<figure><img src="/files/0nOIjWVsxEvy0JJMTiUl" alt=""><figcaption><p>Screenshot of merging records in HubSpot</p></figcaption></figure>

From Whalesync's perspective, here's what happens when merging records:

* HubSpot deletes both of the original records
* HubSpot creates a new record with the properties of the two original records merged in

If you're syncing records to a spreadsheet like Airtable, Google Sheets, or Notion, the following will happen:

* Whalesync will delete both of the original records
* Whalesync will create a new record

If you're using the merge record feature of HubSpot, **please take care if you have non-synced fields** in your spreadsheet, since the **original spreadsheet records will be deleted**.


# Memberstack

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>✉️ Email</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Login redirect</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Permissions</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🆔 Plan IDs</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ Custom fields</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ Metadata</td><td><span data-option="9b0955a85d044258a10aa0d1d3695a79">✅ Supported (as JSON)</span></td><td></td></tr><tr><td>🆔 Memberstack record ID</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🕠 Created at</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🕠 Last login</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🗃️ Plans Data</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>☑️ Verified</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>󠁻󠁻🗃️ JSON</td><td><span data-option="9b0955a85d044258a10aa0d1d3695a79">✅ Supported (as JSON)</span></td><td></td></tr></tbody></table>

## Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

### Auto-generated passwords

{% hint style="info" %}
**Creating a new user via sync, will auto-generate a password in Memberstack**
{% endhint %}

Whalesync allows you to create new Memberstack members from a synced app. For example, you can create a new member from Airtable :tada:.

When creating a new member in Airtable, Whalesync auto-generates a password for that Member. That new member will need to reset their password to log in.

### Syncing custom fields

{% hint style="info" %}
**To sync custom fields, you will need to create a member in Memberstack with the email "<schema@whalesync.com>" with values in custom fields.**
{% endhint %}

See :point\_down:for more details

{% content-ref url="/pages/A8f6LTBhRfG2lVgneQhk" %}
[Memberstack custom fields](/connectors/memberstack/memberstack-custom-fields)
{% endcontent-ref %}

### Default sync delay

{% hint style="info" %}
**If syncing Memberstack and Airtable, we default to a 10-second sync delay from Airtable to Memberstack**
{% endhint %}

See :point\_down:for more details

{% content-ref url="/pages/jfPPLfKhxnLSzCyFRP74" %}
[Creating users via Whalesync](/features/additional-features/creating-users-via-whalesync)
{% endcontent-ref %}

### Metadata fields

{% hint style="info" %}
**Metadata fields sync as JSON**
{% endhint %}

We support 2-way syncing of Memberstack Metadata fields as JSON blobs. You can edit the data in those fields as long as they retain the correct JSON format.

<figure><img src="/files/G8HK1G8JIN2igwR7bj0P" alt=""><figcaption></figcaption></figure>

## Templates <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

Copy our Airtable or Notion templates to instantly have a table set up to sync with Memberstack.

{% embed url="<https://whalesync.com/template-packs>" %}


# Authorize Memberstack

To authorize Memberstack, you just need to grab your App's Secret Key:

<figure><img src="/files/d5T5OlsPzOddKdkjd4RY" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
\*Note - Memberstack has different Secret Keys for your Test data and your Production data. Make sure to choose the one you want.
{% endhint %}


# Memberstack custom fields

How to sync Memberstack custom fields

Memberstack custom fields are supported differently in their API than other fields. In order to sync custom fields, you need to create a member in Memberstack with the email "<schema@whalesync.com>".

Once you create that member, add the custom fields you want to sync and **make sure to put values in those fields**.

{% embed url="<https://www.loom.com/share/eecc3fefe0b74f8584fa3d2e3c41ec58?sid=724ac704-f427-4acb-8ba5-95690d9f5b45>" %}


# Notion

## Notion Connector Guide

This guide provides an overview of how to connect Whalesync to Notion and answers common questions.

### Connecting to Notion

To connect Whalesync to Notion, you will need to authenticate using your Notion account. This process uses OAuth, which is a secure way to grant Whalesync access to your data without sharing your password.

When you authorize the connection, you will be taken to Notion's website. There, you can select which workspace and which specific pages or databases you want Whalesync to be able to access. Whalesync will only have permission to read and write to the pages and databases you explicitly select.

### Syncing Data

Whalesync enables two-way synchronization for most Notion fields. This means that if you update a record in Notion, the change will be reflected in the connected application, and if you update a record in the other application, the change will be reflected in Notion.

Some fields in Notion, such as `Created time` or `Last edited by`, are inherently read-only. Whalesync can read data from these fields and sync it to other apps, but cannot write new data into them. For a detailed list of what is supported, please see the "Supported Fields" section below.

#### Automatic Table and Field Creation

Whalesync can automatically create tables and fields in Notion to match the structure of the other app you're syncing with.

### Things to Keep in Mind

#### Relation fields

Whalesync supports relation fields out of the box! Note - Notion requires the "Two-way relation" option to be toggled in order for them to work.

![](/files/Wc6u1vbiwgKSRhvN17gU)

#### Page Content Syncing

Whalesync can [sync the full content of your Notion pages](/connectors/notion/notion-page-sync). However, there are limitations for pages with very high complexity (i.e. a large number of nested blocks). If you have issues syncing complex pages, please contact support.

Note that the Notion API is significantly slower than most other APIs. When syncing page content across large databases (thousands of pages), sync times can be much longer than usual because each page requires multiple API calls to fetch its full block content. For best performance, keep your synced Notion databases small and focused. See [Notion page sync](/connectors/notion/notion-page-sync) for more details.

#### Rollup Fields

Syncing data from Notion's rollup fields is not yet supported.

#### Auto-Creating Databases

If you use Whalesync's "Auto-create tables" feature to create a new database in Notion, you will need to have specified a parent page when authenticating with Notion. This tells Whalesync where to place the new database.

### Synthetic Fields

Whalesync adds a few read-only fields to your Notion data to help manage the sync. These fields are not present in Notion itself but are available in Whalesync.

| Field Name       | Description                                                                                       | Writable |
| ---------------- | ------------------------------------------------------------------------------------------------- | -------- |
| Notion Record ID | The unique identifier for a page in Notion. This is used by Whalesync to track records.           | No       |
| Page Content     | The full content of a Notion page, including text, images, and other blocks, represented as HTML. | No       |
| Created At       | The timestamp of when a record was first created by the sync.                                     | No       |
| Updated At       | The timestamp of when a record was last updated by the sync.                                      | No       |

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🤖 AI field</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>☑️ Checkbox</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🧑 Created by</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🕠 Created time</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📅 Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>✉️ Email</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 Files &#x26; Media</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📊 Formula</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🧑 Last edited by</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🕠 Last edited time</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🏷️ Multi-Select</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Page content</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🫂 Person</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📞 Phone</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Relation</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🌀 Rollup</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>🔽 Select</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🟢 Status</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔗 URL</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>

## &#x20;<a href="#h_bccce14d8a" id="h_bccce14d8a"></a>


# Notion page sync

Sync the contents of Notion pages to write blog posts and more

<figure><img src="/files/VvhxIbiAXgQnzkv9Z8du" alt=""><figcaption></figcaption></figure>

### About Notion Page Sync

Notion Page Sync is one of Whalesync's most powerful Notion features. As you might have guessed, it allows you to sync data from Notion pages to rich text fields in other apps!

This enables you to write entire blog posts in Notion and sync them instantly to your live blog or site. You can even use Notion AI to write these posts for you.

### When to use Notion Page Sync

Notion Page Sync works best when Notion is the original source of your content. This is because Whalesync can reliably convert Notion's block-based format into HTML for other apps, and when that content is edited elsewhere, we can preserve and map it back to Notion's structure. However, the reverse isn't true—arbitrary HTML from other sources can't always be converted into Notion's proprietary block format. As a result, you might find that some of your styling or custom HTML is lost when sending updates back to your website.

If you only need content to flow *into* Notion from another app, try using a one-way sync on just the Page Content column or the whole table.

### Notion page content vs. Notion records

A Notion database has a list of records. If you open one of those records, it opens up a page. That page is what Whalesync considers "Notion page content":

<figure><img src="/files/trLzYghmwI4V9Ckvgsgd" alt=""><figcaption></figcaption></figure>

### How to set up Notion page sync

To use Notion page sync, simply map the "Page Content" field on the field mapping page. This typically maps to a rich text field in other apps like Webflow.

<figure><img src="/files/uRVmN3SO9QLFZRjhmpLG" alt=""><figcaption></figcaption></figure>

### Things to keep in mind

{% hint style="info" %}
Notion page sync pairs really well with our [Webflow Status field extension](/connectors/webflow/webflow-status-field) feature if syncing Notion -> Webflow
{% endhint %}

{% hint style="info" %}
**Notion page content supports 2-way syncing** meaning you can sync content both from Notion to other apps and from other apps back to Notion
{% endhint %}

{% hint style="info" %}
If syncing Notion pages to the Webflow CMS, **some content may not appear in the Webflow CMS but WILL appear on your live site**. Webflow's CMS doesn't always interpret HTML properly, but web pages will.
{% endhint %}

{% hint style="warning" %}
**Shared OAuth settings**: Notion OAuth has only one set of settings per Notion account, which means all your Whalesync bases will always share the same OAuth permissions. If you have multiple bases and reauthorize one of them (changing which databases you're sharing), it will automatically update the shared databases for all your other bases as well.
{% endhint %}

{% hint style="warning" %}
**Performance with large databases**: The Notion API is significantly slower than most other APIs that Whalesync integrates with. When syncing page content, Whalesync must make multiple API calls per page to fetch all the blocks and nested content. For databases with thousands of pages, this can result in long sync times. If you're experiencing slow syncs, consider moving the pages you want to sync into a smaller, dedicated Notion database with only the records you need. This reduces the number of API calls per polling round and can dramatically improve sync speed.
{% endhint %}

{% hint style="warning" %}
**Page content limitations when syncing INTO Notion**:

* **200 block limit**: Each Notion page is limited to 200 blocks when syncing into Notion
* **No style preservation**: Classes and styles are not preserved when syncing into Notion
  {% endhint %}

<figure><img src="/files/TyZHQ2cepA74pBjBI1Hg" alt=""><figcaption></figcaption></figure>

### Supported blocks

If there are blocks or media formats that you need but do not see listed below, please reach out to <support@whalesync.com>. We are always looking for ways to improve the product!

{% hint style="info" %}
**How unsupported blocks are handled**: Blocks that are not supported will be ignored during the sync process. These blocks will not be deleted or updated in Notion unless their parent object is deleted. They will simply remain unchanged in your Notion page.
{% endhint %}

<table><thead><tr><th>Block</th><th>Status<select><option value="b22bf9be887443049ab27a662e9d8a0c" label="✅ Supported" color="blue"></option><option value="d0b30e9802464ef68f948996577c67df" label="✖️ Not Supported" color="blue"></option><option value="297590c1d191421ba907116eb63e2899" label="✅ Supported - Embedded Images Only" color="blue"></option><option value="0669e7eb92b64963b8cee1ec2a0dd743" label="✅ Supported - Embedded Content Only" color="blue"></option></select></th></tr></thead><tbody><tr><td>📝 Paragraph</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>💪 Headings (h1-h3)</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🖼️ Images (png, jpg, gif, svg, unsplash)</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🔗 Links</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>📹 Video (mp4, ogg, webm, youtube, vimeo, wistia)</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>⚫ Bulleted list</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>⚪ Sub-bulleted list</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>1️⃣ Numbered list</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🇦Sub-numbered list</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🎤 Quote</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>⌨️ Code inline</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>⌨️ Code block</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🔈Audio (mp3, ogg)</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>☑️ To-do list</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>➖ Divider</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>⬇️ Toggle</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🔖 Bookmark</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>📊 Table</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🗣️ Call outs</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>📐 Column list/Column</td><td><span data-option="b22bf9be887443049ab27a662e9d8a0c">✅ Supported</span></td></tr><tr><td>🔄 Synced blocks</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>📋 Template</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>🍞 Breadcrumb</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>📑 Table of contents</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>📄 Child page</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>🗃️ Child database</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>🔗 Link to page</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>🔗 Link preview</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>🔢 Equation</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>📎 PDF</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>📁 File</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr><tr><td>👇 Mention</td><td><span data-option="d0b30e9802464ef68f948996577c67df">✖️ Not Supported</span></td></tr></tbody></table>

{% hint style="info" %}
**Captions can be used to add alt text to images**

We support the alt property on the image html tag and use the caption text for its value. We use the embed html tag for Unsplash images (because doesn't work otherwise) and the image tag for all other images.
{% endhint %}


# Multiple data sources

How to resolve the "Databases with multiple data sources are not supported" error in Whalesync

### `Databases with multiple data sources are not supported in this API version.`

On September 3, 2025, Notion updated their API to allow [multiple data sources](https://www.notion.com/help/data-sources-and-linked-databases) per database. A data source is a set of pages in a database — so a single database can now contain several independent collections of pages.

Whalesync fully supports multiple data sources on all **newly created** syncs. However, this change is **not backward-compatible** with syncs that were created before the update.

If you're seeing the error above, you have two options:

### Option 1: Create a new sync

Create a new sync in Whalesync. New syncs use the latest Notion API version and support multiple data sources out of the box.

### Option 2: Remove extra data sources in Notion

If you'd prefer to keep your existing sync, you can remove any additional data sources from the Notion database so that it only contains a single data source.

To do this, open the database's view settings and click **Manage data sources**:

<figure><img src="/files/sA8spQiqNNOTV0wL8GDz" alt=""><figcaption><p>Open view settings, then click "Manage data sources"</p></figcaption></figure>

Then click the **•••** menu next to the extra data source and choose **Move to** to relocate it to another database:

<figure><img src="/files/6cGXesrDjomPDcrM6BiL" alt=""><figcaption><p>Use the ••• menu to move or delete extra data sources</p></figcaption></figure>

{% hint style="info" %}
Once a database has only one data source, the existing sync will work as before.
{% endhint %}


# Pipedrive

## Supported Objects

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🤝 Deals</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👤 Persons</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👥 Organizations</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🏃‍♂️ Activities</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🎛️ Pipelines</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>📊 Stages</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👥 Users</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👤 Leads</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr></tbody></table>

## Things to Keep in Mind

### Leads sync speed

{% hint style="info" %}
Syncing may be slightly slower for the "Leads" object as Pipedrive does not support webhooks for Leads.
{% endhint %}

### Syncing Pipelines

{% content-ref url="/pages/1kGKIXqyZRmTNX454204" %}
[Pipelines](/connectors/pipedrive/pipelines)
{% endcontent-ref %}


# Pipelines

How to sync specific pipelines in Pipedrive

{% embed url="<https://www.loom.com/share/f4320028d5fd4a7db0271262e38c750a?sid=4c1e1cea-1012-47ad-a3ac-d7c50c41a114>" %}


# Postgres

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🏷️ Array</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Bigint</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Bit</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Boolean</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Composite</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📅 Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📅 Daterange</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔗 Domain</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔘 Enum</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Foreign Key</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Geometric</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>#️⃣ Integer</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Interval</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🗃️Json</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>💱 Money</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Network</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Numeric</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>⏱️ Range</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📝 Text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Textsearch</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>⏱️ Time</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>⏱️ Timestamp</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🆔 Uuid</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ XML</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Binary</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

## Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

### During Setup

{% hint style="warning" %}
**All Postgres tables must have a primary key**\
We use the primary key to keep your data in sync. See [Postgres snippets](/connectors/postgres/primary-key-snippets) for additional detail.
{% endhint %}

{% hint style="warning" %}
**Primary keys must be auto-generated**\
Make sure your primary keys are generated by your database (i.e. have a default value). See [Postgres snippets](/connectors/postgres/primary-key-snippets) for additional detail.
{% endhint %}

{% hint style="warning" %}
**Double-check that the Postgres account you use with Whalesync has access** **to the tables you want to map.**
{% endhint %}

### After Setup

{% hint style="danger" %}
**Renaming schema, tables, or columns will break Whalesync mappings**\
If you rename a table or column, you'll need to remap the impacted table/column in Whalesync. Note - remapping an impacted table will lead to duplicates unless you reset your data as well.
{% endhint %}

### **Handy Tips**

{% hint style="info" %}
**We support foreign keys (including two-way sync)!**\
Make sure to map both tables and reach out for help if not sure how to set it up.
{% endhint %}

{% hint style="info" %}
**Adding ".html" or "\_html" to the end of a column name will preserve HTML**\
If you name a Postgres column something such as "text\_html", Whalesync will preserve that column's values as HTML while syncing.
{% endhint %}


# Authorize Postgres

Whalesync uses a [Postgres connection URI](https://www.postgresql.org/docs/current/libpq-connect.html#id-1.7.3.8.3.6) to connect to a database instance. The following pages describe how to find your connection URI from popular hosting services. If you don't see your hosting service, explore some of the other examples. Your hosting service should be something similar.

Depending on your settings, the connection string may need additional query parameters. You can add query parameters to the end of the URI by adding a question mark ("`?`"), followed by an option name, the equals sign, and a value. Additional parameters then are separated by an ampersand ("`&`"), followed by an option name, the equals sign, and a value. For example:

```
postgresql://postgres@hostname:5432/postgres?sslmode=require&client_encoding=auto
```

Depending on the service, you may need to experiment with different query parameters (especially those with SSL).

When encountering SSL or certificate issues, the "sslmode=no-verify" URL query parameter usually does the trick:

```
postgresql://postgres@hostname:5432/postgres?sslmode=no-verify
```

Please refer to your hosting service's documentation for the recommended settings. For more information regarding the possible query parameters you may need, please refer to these resources:

* <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING>
* <https://github.com/brianc/node-postgres/tree/master/packages/pg-connection-string#tcp-connections>

Note that Whalesync does not yet support:

* Whitelisted IP addresses
* Custom SSL/TLS certificates

If you need these to connect to your instance, please [reach out and let us know](/resources/support).


# AWS (RDS)

How to find get your Postgres connection URI when using Amazon Web Services RDS

## Step 1: Find your database

Navigate to the AWS RDS dashboard. In the left panel you should see "Databases":

<figure><img src="/files/76tmF5wEt26vuhIE3AhI" alt="Screenshot of the AWS RDS side panel"><figcaption><p>Databases page</p></figcaption></figure>

In this list, select your database:

<figure><img src="/files/lOrO08cQJuHen5D8Y6D6" alt="Screenshot of the AWS RDS database list"><figcaption><p>Database list in RDS</p></figcaption></figure>

## Step 2: Construct the connection URI

On the main database page, you should have the "Connectivity & security" tab selected. Note the endpoint and port number:

<figure><img src="/files/x0st1l4bjIMWLWUMLpag" alt="Screenshot of the AWS RDS endpoint and port information"><figcaption><p>RDS endpoint and port number</p></figcaption></figure>

Next under the "Configuration" tab, look up the username. You can also create a different user for Whalesync to connect, but for simplicity we'll use the master username:

<figure><img src="/files/Gp3RdjgXcV3ddYi0tLG4" alt="Screenshot of AWS RDS database configuration"><figcaption><p>RDS configuration with the username</p></figcaption></figure>

The password was set when the database was originally created. Please ask whoever set up the database for the connection password.

Finally, construct the connection URI like this and replace `YOUR_PASSWORD` with the password:

{% code overflow="wrap" %}

```
postgresql://postgres:YOUR_PASSWORD@postgres-connector-test.000000000000.us-east-1.rds.amazonaws.com:5432/postgres
```

{% endcode %}

This is the string you will paste into the Whalesync Postgres connection dialog:

<figure><img src="/files/k0B6suZIO0hJ5TsovB6q" alt="Screenshot of the Whalesync Postgres connection dialog"><figcaption><p>Enter your Postgres connection URI into Whalesync</p></figcaption></figure>

## Caveats

Note that Whalesync does not yet support:

* Whitelisted IP addresses
* Custom SSL/TLS certificates

If you need these to connect to your instance, please [reach out and let us know](/resources/support).


# Basedash

How to find get your Postgres connection URI when using Basedash

<figure><img src="/files/NOnwuOxSNPf3e0oZY4lR" alt=""><figcaption></figcaption></figure>

## Step 1: Find your database

Navigate to the [Basedash Connections page](https://app.basedash.com/connections). In the left panel, scroll down to the bottom to see your databases. Click on the gear icon of the database you want to connect:

<div align="center"><figure><img src="/files/zQ4FDbzQV5MJl7NA0VTf" alt="Screenshot of the settings icon for a database connection in Basedash"><figcaption><p>Connection settings for a database</p></figcaption></figure></div>

Click "Manage credentials":

<figure><img src="/files/2zez6Ku0PUdANwe74yr6" alt="Screenshot of the manage credentials button in Basedash"><figcaption><p>Manage credentials for a database</p></figcaption></figure>

## Step 2: Construct the connection URI

On the "Manage credentials" page, you should see a "SQL connection overview" section:

<figure><img src="/files/rB0AbN72jzugLjECvem7" alt="SQL connection overview page in Basedash"><figcaption><p>SQL connection overview</p></figcaption></figure>

Construct the connection URI with the above fields and replace `YOUR_PASSWORD` with the correct password. Using the example values above, the connection URI would look like this:

{% code overflow="wrap" %}

```
postgresql://postgres:YOUR_PASSWORD@18.18.98.1:5432/postgres
```

{% endcode %}

This is the string you will paste into the Whalesync Postgres connection dialog:

<figure><img src="/files/OxVCGLQ2PxPOr6msM9ez" alt="Screenshot of the Whalesync Postgres connection dialog"><figcaption><p>Enter your Postgres connection URI into Whalesync</p></figcaption></figure>

## Caveats

Note that Whalesync does not yet support:

* Whitelisted IP addresses
* Custom SSL/TLS certificates

If you need these to connect to your instance, please [reach out and let us know](/resources/support).


# DigitalOcean

To authorize DigitalOcean, you'll need to set `sslmode=no-verify` in the connection string.


# Heroku

To authorize Heroku, you'll need to set `sslmode=no-verify` in the connection string.


# Neon

How to get connection string from Neon

### Step 1: From your Dashboard, go to the Project you want to sync

<figure><img src="/files/wyq0HcQBlKefJX7ymdRb" alt=""><figcaption></figcaption></figure>

### Step 2: In your project's dashboard, click the '**Connect'** button

<figure><img src="/files/MeKcSvddlAX0GY7Ly3LB" alt=""><figcaption></figcaption></figure>

### Step 3: Copy your connection string

<figure><img src="/files/KMShrGyQDVv4OKG0CE3r" alt=""><figcaption></figcaption></figure>


# Render

How to find get your Postgres connection URI when using Render

## Step 1: Find your database

Navigate to the [Render dashboard](https://dashboard.render.com/). You should see a list of databases. Click on the one you want to connect:

<figure><img src="/files/iFwNbsJq6CsrC5oC3qvG" alt="Screenshot of the Render dashboard"><figcaption><p>Render dashboard</p></figcaption></figure>

## Step 2: Find your connection URI

On the "Info" page, scroll down to "Connections". Next to "External Database URL", click the "Copy to clipboard" button:

<figure><img src="/files/ELEiFHE3qVQcBv00qZA7" alt="Screenshot of the Render database connections section with the external database URL"><figcaption><p>External Database URL</p></figcaption></figure>

In the Whalesync Postgres connection dialog, paste in the connection URI:

<figure><img src="/files/YiewUHRtV5yF4xZmw65T" alt="Screenshot of the Whalesync Postgres connection dialog"><figcaption><p>Enter your Postgres connection URI into Whalesync</p></figcaption></figure>


# Supabase

How to authorize Supabase

## Step 1: Pick Supabase

<figure><img src="/files/QlkswhGxRHZiGtl0G6IE" alt=""><figcaption></figcaption></figure>

## Step 2: Use Supabase OAuth

<figure><img src="/files/SUwvaZu3GDAdhnxIqS7k" alt=""><figcaption></figcaption></figure>


# SQL scripts

Code to help you quickly create Postgres tables to sync with other apps

{% tabs %}
{% tab title="HubSpot" %}

```sql
CREATE TYPE crm_status AS ENUM (
	'Cold', 
	'Waitlist', 
	'Contacted', 
	'Meeting Complete', 
	'Should Follow Up', 
	'Paying Customer', 
	'Churned');

CREATE TABLE crm (
	id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
	"Contact Name" text,
	"Status" crm_status,
	"Email" text,
	"Company" text,
	"Title" text,
	"Source" text,
	"Twitter" text,
	"LinkedIn" text,
	"Personal Website" text,
	"VIP" boolean,
	"Enthusiasm (1-5)" integer
);

```

{% endtab %}

{% tab title="Shopify" %}

```sql
CREATE TYPE published_scope AS ENUM ('web', 'global');

CREATE TYPE sort_order AS ENUM ('alpha-asc', 'alpha-desc', 'best-selling', 'created', 'created-desc', 'manual', 'price-asc', 'price-desc');

CREATE TYPE state AS ENUM ('disabled', 'invited', 'enabled', 'declined');

CREATE TYPE status AS ENUM ('active', 'archived', 'draft');

CREATE TYPE tax_exemptions AS ENUM ('EXEMPT_ALL', 'CA_STATUS_CARD_EXEMPTION', 'CA_DIPLOMAT_EXEMPTION', 'CA_BC_RESELLER_EXEMPTION', 'CA_MB_RESELLER_EXEMPTION', 'CA_SK_RESELLER_EXEMPTION', 'CA_BC_COMMERCIAL_FISHERY_EXEMPTION', 'CA_MB_COMMERCIAL_FISHERY_EXEMPTION', 'CA_NS_COMMERCIAL_FISHERY_EXEMPTION', 'CA_PE_COMMERCIAL_FISHERY_EXEMPTION', 'CA_SK_COMMERCIAL_FISHERY_EXEMPTION', 'CA_BC_PRODUCTION_AND_MACHINERY_EXEMPTION', 'CA_SK_PRODUCTION_AND_MACHINERY_EXEMPTION', 'CA_BC_SUB_CONTRACTOR_EXEMPTION', 'CA_SK_SUB_CONTRACTOR_EXEMPTION', 'CA_BC_CONTRACTOR_EXEMPTION', 'CA_SK_CONTRACTOR_EXEMPTION', 'CA_ON_PURCHASE_EXEMPTION', 'CA_MB_FARMER_EXEMPTION', 'CA_NS_FARMER_EXEMPTION', 'CA_SK_FARMER_EXEMPTION');

CREATE TABLE public."Collects"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Collection" uuid,
"Created at" timestamp without time zone,
"Position" decimal,
"Product" uuid,
"Shopify Record ID" text,
"Updated at" timestamp without time zone
);

CREATE TABLE public."Custom Collections"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Description" text,
"Handle" text,
"Image" text,
"Published at" timestamp without time zone,
"Shopify Record ID" text,
"Sort order" sort_order,
"Title" text,
"Updated at" timestamp without time zone
);

CREATE TABLE public."Customers"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Addresses" text,
"Created at" timestamp without time zone,
"Default address" text,
"Email" text,
"Email marketing consent" text,
"First name" text,
"Last name" text,
"Last Order" text,
"Multipass identifier" decimal,
"Note" text,
"Orders count" decimal,
"Password" text,
"Password confirmation" text,
"Phone" text,
"Shopify Record ID" text,
"Sms marketing consent" text,
"State" state,
"Tax Exemption" boolean,
"Tax exemptions" tax_exemptions[],
"Total spent" decimal,
"Updated at" timestamp without time zone,
"Verified email" boolean
);

CREATE TABLE public."Images"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Created at" timestamp without time zone,
"Height" decimal,
"Image" text,
"Position" decimal,
"Shopify Record ID" text,
"Updated at" timestamp without time zone,
"Width" decimal
);

CREATE TABLE public."Options"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Name" text,
"Position" decimal,
"Shopify Record ID" text,
"Values" text[]
);

CREATE TABLE public."Products"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Created at" timestamp without time zone,
"Default Image" text,
"Description" text,
"Handle" text,
"Images_fk_Images" uuid[],
"Options_fk_Options" uuid[],
"Point of Sale" published_scope,
"Product type" text,
"Published at" timestamp without time zone,
"Shopify Record ID" text,
"Status" status,
"Tags" text[],
"Template suffix" text,
"Title" text,
"Updated at" timestamp without time zone,
"Variants_fk_Variants" uuid[],
"Vendor" text
);

CREATE TABLE public."Variants"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Barcode" text,
"Created at" timestamp without time zone,
"Image" uuid,
"Inventory quantity" decimal,
"Option 1" text,
"Option 2" text,
"Option 3" text,
"Position" decimal,
"Price" decimal,
"Shopify Record ID" text,
"Sku" text,
"Title" text,
"Updated at" timestamp without time zone,
"Weight (g)" decimal,
"Weight (lb)" decimal
);

ALTER TABLE public."Collects"
ADD CONSTRAINT collects_collection_custom_collections_fkey
FOREIGN KEY ("Collection")
REFERENCES public."Custom Collections"("id");

ALTER TABLE public."Collects"
ADD CONSTRAINT collects_product_products_fkey
FOREIGN KEY ("Product")
REFERENCES public."Products"("id");

ALTER TABLE public."Variants"
ADD CONSTRAINT variants_image_images_fkey
FOREIGN KEY ("Image")
REFERENCES public."Images"("id");
```

{% endtab %}

{% tab title="WordPress" %}

```sql
CREATE TYPE comment_status AS ENUM ('open', 'closed');

CREATE TYPE format AS ENUM ('standard', 'aside', 'chat', 'gallery', 'link', 'image', 'quote', 'status', 'video', 'audio');

CREATE TYPE media_type AS ENUM ('image', 'file');

CREATE TYPE ping_status AS ENUM ('open', 'closed');

CREATE TYPE status AS ENUM ('publish', 'future', 'draft', 'pending', 'private', 'acf-disabled', 'inherit');

CREATE TYPE taxonomy AS ENUM ('category', 'post_tag');

CREATE TABLE public."Categories"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Count" integer,
"Description" text,
"Link" text,
"Name" text,
"Slug" text,
"Taxonomy" taxonomy,
"WordPress.org Record ID" text
);

CREATE TABLE public."Media"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Alt text" text,
"Author" uuid,
"Caption" text,
"Comment status" comment_status,
"Date" timestamp without time zone,
"Description" text,
"Link" text,
"Media details" text,
"Media type" media_type,
"Mime type" text,
"Modified" timestamp without time zone,
"Ping status" ping_status,
"Slug" text,
"Source url" text,
"Status" status,
"Title" text,
"WordPress.org Record ID" text
);

CREATE TABLE public."Pages"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Author" uuid,
"Comment status" comment_status,
"Content" text,
"Date" timestamp without time zone,
"Excerpt" text,
"Featured media" uuid,
"Link" text,
"Menu order" integer,
"Modified" timestamp without time zone,
"Ping status" ping_status,
"Slug" text,
"Status" status,
"Title" text,
"WordPress.org Record ID" text
);

CREATE TABLE public."Posts"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Author" uuid,
"Categories" uuid,
"Comment status" comment_status,
"Content" text,
"Date" timestamp without time zone,
"Excerpt" text,
"Featured media" uuid,
"Format" format,
"Link" text,
"Modified" timestamp without time zone,
"Ping status" ping_status,
"Slug" text,
"Status" status,
"Sticky" boolean,
"Tags" uuid,
"Title" text,
"WordPress.org Record ID" text
);

CREATE TABLE public."Tags"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Count" integer,
"Description" text,
"Link" text,
"Name" text,
"Slug" text,
"Taxonomy" taxonomy,
"WordPress.org Record ID" text
);

CREATE TABLE public."Users"(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Avatar urls" text,
"Description" text,
"Link" text,
"Name" text,
"Slug" text,
"Url" text,
"WordPress.org Record ID" text
);

ALTER TABLE public."Media"
ADD CONSTRAINT media_users_fkey
FOREIGN KEY ("Author")
REFERENCES public."Users"("id");

ALTER TABLE public."Pages"
ADD CONSTRAINT pages_media_fkey
FOREIGN KEY ("Featured media")
REFERENCES public."Media"("id");

ALTER TABLE public."Pages"
ADD CONSTRAINT pages_users_fkey
FOREIGN KEY ("Author")
REFERENCES public."Users"("id");

ALTER TABLE public."Posts"
ADD CONSTRAINT posts_categories_fkey
FOREIGN KEY ("Categories")
REFERENCES public."Categories"("id");

ALTER TABLE public."Posts"
ADD CONSTRAINT posts_media_fkey
FOREIGN KEY ("Featured media")
REFERENCES public."Media"("id");

ALTER TABLE public."Posts"
ADD CONSTRAINT posts_tags_fkey
FOREIGN KEY ("Tags")
REFERENCES public."Tags"("id");

ALTER TABLE public."Posts"
ADD CONSTRAINT posts_users_fkey
FOREIGN KEY ("Author")
REFERENCES public."Users"("id");
```

{% endtab %}
{% endtabs %}


# Primary key snippets

Handy snippets to help you set up Postgres to work with Whalesync

{% tabs %}
{% tab title="Primary Key - Create" %}
The best way to create the primary key is to define it as part of creating a table. In the example below, there are two options: one using UUIDs and another using integers as primary keys (the latter is commented out). In both cases the primary key is set to auto-generate a key when a record is inserted into the table.

{% code overflow="wrap" %}

```sql
CREATE TABLE public."Table" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
--id serial PRIMARY KEY,
"description" text,
"is_published" boolean );
```

{% endcode %}
{% endtab %}

{% tab title="Primary Keys – Alter" %}
If the table already exists and you want to change the primary key, you'll need to remove the old one and add a new one.

```sql
-- Delete the old primary key.
ALTER TABLE public."Table" 
DROP COLUMN "id";
-- Add a new generated primary key.
ALTER TABLE public."Table" 
ADD COLUMN "uuid" uuid PRIMARY KEY DEFAULT gen_random_uuid();
```

If the table already exists and you already have a generated key and want to designate it as a primary key.

```sql
ALTER TABLE public."Table"
ADD CONSTRAINT table_pk PRIMARY KEY ("uuid");
```

*\*Supabase blocks access to altering a table outside of its UI, thus please use Supabase's UI.*
{% endtab %}

{% tab title="Primary Key – Generate" %}
Whalesync requires that the primary key is generated (i.e. has an automatic default value). These are a few examples of functions that would generate data for you:

```
uuid_genetate_v4()
```

```
gen_random_uuid()
```

```
nextval('column_name')
```

We also support serial integers as the primary column (these are self-incrementing integers and equivalent to using the `nextval` function).
{% endtab %}
{% endtabs %}


# Foreign key snippets

Handy snippets to help you set up Postgres to work with Whalesync

{% tabs %}
{% tab title="Foreign Keys - Add" %}
Whalesync supports foreign keys. After creating your tables, you can designate a foreign key and then point it to another table's primary key.

```sql
ALTER TABLE public."Table"
ADD CONSTRAINT table_category_fkey
FOREIGN KEY ("category")
REFERENCES categories("name");
```

In the example above we are adding to a table called "Table" to an existing column called "category" a foreign key pointing to column called "name" in a table called "categories". The example creates the foreign key relationship, it does not create any tables and columns, they must already all exist.
{% endtab %}

{% tab title="Foreign Keys - Arrays" %}
**About foreign key arrays**

Unfortunately, Postgres does not support arrays of foreign keys. Some of the other apps we connect with (e.g. Airtable) do, so we've tried to build a workaround for this. With this workaround you'll be able to sync Airtable linked records with a fake Postgres foreign key array.

**How it works**

At a high-level, you can configure a Postgres column to be an array BUT signal to Whalesync that you'd like us to treat it as a foreign key array.

Since Postgres just sees this as an array, the field no longer has the same validation, but it will sync.

{% hint style="info" %}
**Note:** a bad value here will not break Whalesync, that value will simply not sync until you correct it.
{% endhint %}

**How do I implement this?**

Imagine you have two tables:

* Contacts
* Company

To create a foreign key array you can:

1. Ensure both tables have a primary key (e.g. uuid)
2. In Company, create an array column "People\_fk\_Contacts" with type uuid\[] to match the type of the table id.

   1. The "\_fk" designates to Whalesync that you want this to be a foreign key.
   2. The "\_Contacts" designates that it should point to the Contacts table.

   (\*note - must match capitlization)
3. Set up your sync in Whalesync as normal, mapping your fields.

**Example snippet**

```sql
CREATE TABLE public."Contacts" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Email" text );

CREATE TABLE public."Company" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Name" text,
"People_fk_Contacts" uuid[] );
```

{% endtab %}
{% endtabs %}


# Terminology

Definitions of the Postgres terminology we use in our errors and messaging

<table><thead><tr><th width="192">Term</th><th width="345.3333333333333">Definition</th><th>Postgres Documentation</th></tr></thead><tbody><tr><td>Primary Key</td><td>A column or group of columns that can be used to uniquely identify a row in a table. This requires that the values be both unique and not empty.</td><td><a href="https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-PRIMARY-KEYS">5.4.4. Primary Keys</a></td></tr><tr><td>Foreign Key</td><td>A column that matches the value appearing in a column of another table and maintains the referential integrity between two related tables.</td><td><a href="https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK">5.4.5. Foreign Keys</a></td></tr><tr><td>Generated Column</td><td>Whalesync requires that your primary key has a default value generated via a function. This guarantees that there will be a value even if you don't map the primary key column.</td><td><a href="https://www.postgresql.org/docs/current/ddl-default.html">5.2. Default Values</a></td></tr></tbody></table>

Whalesync requires that every table you map has a **single** primary key and that it is generated because it is essential that we can uniquely identify a row of data every time in order to be able to sync it correctly to or from another application. The primary key guarantees uniqueness and the generation means there will always be a good, viable value.

See [Postgres snippets](/connectors/postgres/primary-key-snippets) for helpful generation functions as well as defining the primary and foreign keys of a table.


# Multiple foreign keys in a single field

This describes how to sync a multi-foreign key field in another app (e.g. Airtable) to Postgres or Supabase

### **About foreign key arrays**

Unfortunately, Postgres (including Supabase) does not support arrays of foreign keys. Some of the other apps we connect with (e.g. Airtable) do, so we've tried to build a workaround for this. With this workaround you'll be able to sync Airtable linked records with a fake Postgres foreign key array.

### **How it works**

At a high-level, you can configure a Postgres/Supabase column to be an array BUT signal to Whalesync that you'd like us to treat it as a foreign key array.

Since Postgres just sees this as an array, the field no longer has the same validation, but it will sync.

{% hint style="info" %}
**Note:** a bad value here will not break Whalesync, that value will simply not sync until you correct it.
{% endhint %}

### **How do I implement this?**

Imagine you have two tables:

* Contacts
* Company

To create a foreign key array you can:

1. Ensure both tables have a primary key (e.g. uuid)
2. In Company, create an array column "People\_fk\_Contacts" with type uuid\[] to match the type of the table id.

   1. The "\_fk" designates to Whalesync that you want this to be a foreign key.
   2. The "\_Contacts" designates that it should point to the Contacts table.

   (\*note - must match capitlization)
3. Set up your sync in Whalesync as normal, mapping your fields.

### **Example snippet**

```sql
CREATE TABLE public."Contacts" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Email" text );

CREATE TABLE public."Company" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"Name" text,
"People_fk_Contacts" uuid[] );
```


# How to sync Postgres views

A quick tutorial on how to sync a Postgres (or Supabase) view with Whalesync

{% embed url="<https://www.loom.com/share/7e33536a9c224120999cfb5b0d274174?sid=1c152ef0-0f51-4243-b093-b38e5f327bc2>" %}


# Salesforce

## Salesforce Connector Guide

This guide provides an overview of how to connect Whalesync to Salesforce and answers common questions.

### Connecting to Salesforce

To connect Salesforce to Whalesync, you will need to authenticate using your Salesforce account. This process uses OAuth 2.0, a standard and secure method for authorization.

When you set up a new Salesforce connection, you will be prompted to log in to your Salesforce account. After logging in, Salesforce will ask you to grant Whalesync permission to access your data. The data that Whalesync can access is determined by the permissions of the Salesforce user who authorizes the connection. We recommend using a Salesforce account with administrative privileges to ensure Whalesync has access to all the objects and fields you intend to sync.

### Syncing Data

#### Salesforce Views

Salesforce allows you to create "Views" to segment your data within an object. For example, you can create a view of "New Leads" in your Leads object. Whalesync can sync with a specific Salesforce View. When setting up your sync, you can choose a view for each Salesforce object you want to sync. This will restrict the synced records to only those that appear in the selected view.

If you do not select a specific view, Whalesync will sync all records in the object.

Please note that some Salesforce objects, such as `Profile` and `RecordType`, do not support views. For these objects, Whalesync will sync all records.

### Things to Keep in Mind

* **Beta Connector**: The Salesforce connector is currently in beta. We are continuously working to improve it.
* **Permissions**: Whalesync's access to your Salesforce data is based on the permissions of the Salesforce user who sets up the connection. If you are unable to see certain objects or fields in Whalesync, ensure the connected user account has the necessary permissions in Salesforce.
* **Backups**: We strongly encourage you to have a backup and restore strategy for your Salesforce data. Two-way data sync is powerful, and having backups provides an extra layer of safety. Salesforce offers backup solutions which you can explore.
* **Restricted Picklists**: If you try to sync a new value to a Salesforce picklist field that has a restricted set of options, you will encounter an error. To resolve this, you can either add the new value as an option to the picklist in your Salesforce settings or remove the restriction from the field.
* **Deleting Records**: Salesforce prevents the deletion of records that are linked to other records through a relationship. For example, you cannot delete an Account if it is still linked to Opportunities. If you encounter an error when trying to delete a record, you will first need to remove its associations with other records in Salesforce.
* **API Usage**: Syncing data uses Salesforce API calls. Salesforce accounts have API call limits based on their edition and number of user licenses. While Whalesync is optimized to use the API efficiently, very large syncs or frequent updates may contribute significantly to your API usage. You can monitor your API usage in the "Company Information" section of your Salesforce setup.
* **Formula Fields**: Formula fields in Salesforce are read-only. Whalesync can read data from these fields, but cannot write data to them.
* **Encrypted Text Fields**: Whalesync supports Encrypted Text fields. Please note that these fields are "write-once", meaning that after a value has been set, it cannot be updated via the API.

### Synthetic Fields

Whalesync adds a few read-only fields to your data to help manage the sync. These fields are "synthetic," meaning they are not part of your original Salesforce data but are added by Whalesync.

| Field Name             | Explanation                                                                            | Writable |
| ---------------------- | -------------------------------------------------------------------------------------- | -------- |
| `Salesforce Record ID` | The unique identifier for a record from Salesforce. This is the Salesforce `Id` field. | No       |

### Supported Objects and Fields

Whalesync supports a wide variety of Salesforce objects and fields.

#### Supported Objects

| Tables                       | Status                         |
| ---------------------------- | ------------------------------ |
| 👤 Account                   | ✅ Supported                    |
| 📊 Campaign                  | ✅ Supported                    |
| :bar\_chart: Campaign Member | ✅ Supported                    |
| :briefcase: Case             | :white\_check\_mark: Supported |
| 👤 Contact                   | ✅ Supported                    |
| 🧳 Custom Object             | ✅ Supported                    |
| 👤 Lead                      | ✅ Supported                    |
| 📈 Opportunity               | ✅ Supported                    |
| 👤 Profile                   | :white\_check\_mark: Supported |
| :e-mail: RecordType          | :white\_check\_mark: Supported |
| ✅ Task                       | ✅ Supported                    |
| 👤 User                      | ✅ Supported                    |

#### Supported Fields

| Fields                          | Status      |
| ------------------------------- | ----------- |
| 💵 Auto Number                  | ✅ Supported |
| 📝 Formula                      | ✅ Supported |
| 🔎 Lookup Relationship          | ✅ Supported |
| 🤝 Master-Detail Relationship   | ✅ Supported |
| 🔎 External Lookup Relationship | ✅ Supported |
| ✅ Checkbox                      | ✅ Supported |
| 💵 Currency                     | ✅ Supported |
| 📅 Date                         | ✅ Supported |
| 🕕 Date/Time                    | ✅ Supported |
| 📧 Email                        | ✅ Supported |
| 🗺️ Geolocation                 | ✅ Supported |
| #️⃣ Number                      | ✅ Supported |
| % Percent                       | ✅ Supported |
| ☎️ Phone                        | ✅ Supported |
| 🗒️ Picklist                    | ✅ Supported |
| 🗒️ Picklist (Multi-Select)     | ✅ Supported |
| 📘 Text                         | ✅ Supported |
| 📘 Text Area                    | ✅ Supported |
| 📘 Text Area (Long)             | ✅ Supported |
| 📘 Text Area (Rich)             | ✅ Supported |
| 📘 Text (Encrypted)             | ✅ Supported |
| 🕧 Time                         | ✅ Supported |
| 🔗 URL                          | ✅ Supported |


# Salesforce view sync

Sync specific views in Salesforce

<figure><img src="/files/Ef88sinD3G3iYM04RtMA" alt=""><figcaption><p>Choosing to map a Salesforce view instead of the entire object</p></figcaption></figure>

### About Salesforce view sync

Salesforce views are filtered subsets of the data in your Salesforce object.

With Salesforce view sync, you can sync specific views instead of the entire object.

### How to use Salesforce view sync

When mapping tables, choose the Salesforce view you'd like to sync instead of the entire table.

<figure><img src="/files/MzmySJSF3KNaXsYFIOv7" alt=""><figcaption></figcaption></figure>


# Stripe

## Stripe Connector Guide

This guide provides an overview of how to connect Whalesync to Stripe and answers common questions.

### Connecting to Stripe

To connect to Stripe, you'll need to [create your Stripe "Secret Key"](https://docs.whalesync.com/connectors/stripe/authorize-stripe). This key is a password that allows Whalesync to securely access your Stripe data.

You can find your Secret Key in your Stripe Dashboard under Developers > API keys. It is important that you copy the **Secret key** (it starts with `sk_...`), not the Publishable key (which starts with `pk_...`). Using a Publishable key will result in an error when you try to connect.

Common connection issues include:

* **Invalid Key**: If you get an error about an invalid key, check that you have copied the full Secret Key correctly.
* **Publishable Key Used**: If you see an authorization error, ensure you are using a Secret Key (`sk_...`) and not a Publishable key (`pk_...`).

For detailed instructions with screenshots, see our guide on [authorizing Stripe](https://docs.whalesync.com/connectors/stripe/authorize-stripe).

### Syncing Data

Whalesync can read data from many different objects in Stripe. Once you've connected your Stripe account, you can choose which of these to sync.

#### Supported Objects

| Tables            | Status               |
| ----------------- | -------------------- |
| 💵 Charges        | ➡️ Supported (1-Way) |
| 💵 Coupons        | ➡️ Supported (1-Way) |
| 👤 Customers      | ➡️ Supported (1-Way) |
| 📃 Invoice Items  | ➡️ Supported (1-Way) |
| 💵 Invoices       | ➡️ Supported (1-Way) |
| 🔗 Payment Links  | ➡️ Supported (1-Way) |
| 📃 Plans          | ➡️ Supported (1-Way) |
| 💵 Prices         | ➡️ Supported (1-Way) |
| 📦 Products       | ➡️ Supported (1-Way) |
| 📣Promotion Codes | ➡️ Supported (1-Way) |
| 💵 Refunds        | ➡️ Supported (1-Way) |
| 📃 Subscription   | ➡️ Supported (1-Way) |

### Things to Keep in Mind

* **Read-Only Sync**: Stripe is a "read-only" connector. This means Whalesync can pull data *from* Stripe into other apps, but cannot push data *to* Stripe. You will not be able to use Whalesync to create or update records in Stripe.
* **Data Formatting**: Some Stripe fields are converted to a more usable format in your destination app:
  * **Amounts**: Stripe stores money values in the smallest currency unit (e.g., cents). For example, a charge of $10.00 is stored as `1000` in Stripe. Whalesync automatically converts this to `10` so it displays as the correct dollar amount in other tools.
  * **Complex Fields**: Some fields in Stripe contain complex data, like a list of items or nested information. Whalesync converts these fields into a text format (JSON) so you can still access the data.

### Synthetic Fields

Whalesync adds a few fields to your data that are not originally from Stripe. These fields help Whalesync manage the sync and provide useful metadata. They are not writable.

| Name                      | Explanation                                                                                              | Writable |
| ------------------------- | -------------------------------------------------------------------------------------------------------- | -------- |
| Stripe Record ID          | A unique ID that Whalesync uses to keep track of records in Stripe. This is based on the ID from Stripe. | No       |
| Last Modified (Whalesync) | The timestamp of when Whalesync last updated the record in the destination app.                          | No       |

The table below lists all the Stripe objects (which Whalesync treats as tables) that you can sync.

### Supported Fields

Whalesync supports a variety of field types from Stripe. Here's a guide to what they mean:

* **String**: Plain text.
* **Integer**: Numbers without decimals.
* **Boolean**: A true/false value.
* **Timestamp**: Date and time information.
* **Currency**: A three-letter code for the currency (e.g., "USD").
* **Money**: A numerical value representing an amount of money.
* **Foreign Key**: A reference to another record. For example, a Charge record might have a Customer ID that links to a Customer record.
* **Expandable**: A special Stripe field that links to another Stripe object (like a Customer or Invoice). Whalesync automatically includes the full details of that linked object, shown as a block of text (JSON).
* **Hash / Array**: Fields that hold structured data, like a list of items. Whalesync converts these into readable text (JSON).
* **Enum**: A field that has a specific list of possible values, like the status of a payment.


# Authorize Stripe

To authorize Stripe, you need to generate an API key:

1. In Stripe, go to the [API keys](https://dashboard.stripe.com/apikeys) section
2. Click "Create secret key"
3. Give the key a name, such as "Whalesync Key"
4. Copy the key into the text box in Whalesync

<figure><img src="/files/eKadQtthTz9YGO0zdGdy" alt=""><figcaption></figcaption></figure>


# Supabase

## Supabase Connector Guide

This guide provides an overview of how to connect Whalesync to Supabase and answers common questions.

### Connecting to Supabase

To connect your Supabase database to Whalesync, you'll need to authenticate using OAuth. This is a secure way to grant Whalesync access to your Supabase data without sharing your password. Whalesync will request access to your Supabase organization. After you select an organization, Whalesync will show you a list of your Supabase projects.

Once you select a project, Whalesync creates [a dedicated read-write service account](/connectors/supabase/why-does-whalesync-create-a-database-user) in that Supabase project. This allows Whalesync to access your data to perform syncs. The service account is granted permissions on the `public` schema by default, which is where it can create and update records.

### Syncing Data

#### Automatic Table and Field Creation

Whalesync can automatically create tables and fields in Supabase to match the structure of the other app you're syncing with.

### Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

#### Primary Keys

For a table to be syncable, it must have a primary key that can uniquely identify each row. Whalesync will automatically detect the primary key on your table. If your table does not have a suitable primary key (e.g., an auto-incrementing number), Whalesync can add a synthetic primary key column to enable syncing.

**Primary keys must be auto-generated** (i.e. have a default value). To ensure data consistency, we require primary keys have default values. See [Adding default values to primary keys](/connectors/supabase/adding-default-values-to-primary-keys).

#### Schema changes

{% hint style="danger" %}
**Renaming schema, tables, or columns will break Whalesync mappings**\
If you rename a table/column, you'll need to remap the impacted table/column in Whalesync.
{% endhint %}

#### Foreign Keys

**We support foreign keys (including two-way sync)!** In order to sync a foreign key *column*, you'll need to also sync the *table* the column references.

#### **Permissions**

The service account created by Whalesync has read and write permissions on the `public` schema. If you want to sync tables in other schemas, you may need to grant permissions to the `whalesync_service_account` role in your Supabase project manually.

#### **Schema Changes**

After making schema changes in Supabase, like adding or removing a column, you should refresh the schema in Whalesync to see those changes reflected.

#### HTML and Markdown

{% hint style="info" %}
**Adding "\_html" to the end of a column name will preserve HTML**\
For example, "text\_html", will preserve that column's values as HTML while syncing.
{% endhint %}

See [HTML and Markdown Field Extensions](/features/additional-features/html-and-markdown-field-extensions) for a way to sync HTML or Markdown into a rich text field.

#### Unsupported

Note that Whalesync does not yet support:

* Whitelisted IP addresses
* Custom SSL/TLS certificates

## Supported Schemas

In general, Whalesync supports syncing custom Supabase tables. We want to prevent interfering with internal Supabase data, so we don't support syncing Postgres schemas that Supabase uses for its own internal purposes.

<table><thead><tr><th>Schema</th><th>Status<select><option value="RQOyUDZdcogv" label="✅ Supported" color="blue"></option><option value="Rfk2xdxRw6D8" label="✖️ Not Supported" color="blue"></option></select></th></tr></thead><tbody><tr><td>public</td><td><span data-option="RQOyUDZdcogv">✅ Supported</span></td></tr><tr><td>Any other non-Supabase provided schema</td><td><span data-option="RQOyUDZdcogv">✅ Supported</span></td></tr><tr><td>auth</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>extensions</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>graphql</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>graphql_public</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>pgbouncer</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>pgsodium</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>pgsodium_masks</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>realtime</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>storage</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr><tr><td>vault</td><td><span data-option="Rfk2xdxRw6D8">✖️ Not Supported</span></td></tr></tbody></table>

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🏷️ Array</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Bigint</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Bit</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Boolean</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Composite</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📅 Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📅 Daterange</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔗 Domain</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔘 Enum</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Foreign Key</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Geometric</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>#️⃣ Integer</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Interval</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🗃️Json</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>💱 Money</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Network</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Numeric</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>⏱️ Range</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📝 Text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Textsearch</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>⏱️ Time</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>⏱️ Timestamp</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🆔 Uuid</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ XML</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔦 Binary</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

## &#x20;<a href="#h_bccce14d8a" id="h_bccce14d8a"></a>


# Getting your connection string

How to find get your Supabase connection string.

{% embed url="<https://youtu.be/LzOdTIZOnaM?si=WzGEFf4C2bBuw8jF>" %}

## Step 1: Choose your database

Navigate to your [Supabase dashboard](https://app.supabase.com/projects) and select the database you want to connect:

<figure><img src="/files/vFEkKELnzcmiIgol1ngG" alt="Screenshot of a database on the Supabase dashboard"><figcaption><p>Pick your database</p></figcaption></figure>

## Step 2: Get your connection string

Click "Connect":

<figure><img src="/files/FK3cqB5eLSO19YDxYPuB" alt=""><figcaption><p>Connect button</p></figcaption></figure>

Copy the full connection string under "Direct connection":

<figure><img src="/files/EfRPAmZ9vqUenst9Kd0Z" alt=""><figcaption><p>Connection string</p></figcaption></figure>

Paste the full connection string into Whalesync.

{% hint style="warning" %}
Replace `[YOUR-PASSWORD]` with your database password.\
\&#xNAN;*(ask a developer on your team if you don't know it)*
{% endhint %}

<figure><img src="/files/EOhRH2kzCVUTMG0mYx8J" alt="Screenshot of the Whalesync Supabase connection dialog"><figcaption><p>Enter your Supabase connection URI into Whalesync</p></figcaption></figure>


# Adding default values to primary keys

How to make your primary keys auto-generate values in Supabase

1. Click on the primary key in your table.
2. Click "Edit column"

   <figure><img src="/files/xKdevyRLbcZPasXgP16b" alt=""><figcaption></figcaption></figure>
3. Change the column type to uuid
4. Set the Default Value equal to <mark style="color:red;">`gen_random_uuid()`</mark>

   <figure><img src="/files/NZaI6l3HPc9xKqOmUVRv" alt=""><figcaption></figcaption></figure>
5. Make sure "Is Unique" is toggled on

   <figure><img src="/files/YyQeF9vUmHx0UltiSvbW" alt=""><figcaption></figcaption></figure>


# How to sync Airtable linked records with Supabase foreign keys

A guide to syncing Airtable's linked record fields with Supabase

{% embed url="<https://www.loom.com/share/176228d21b7b479f9fad8761dba8f5db?sid=6696c752-f965-4bde-88d4-ade7af197936>" %}


# Removing the Whalesync database user

How to remove the Whalesync database user from your Supabase or Postgres project

When you connect Supabase to Whalesync, we create [a dedicated database user](/connectors/supabase/why-does-whalesync-create-a-database-user) in your project so we can read and write only the data you sync. If you stop using Whalesync and want your project fully cleaned up, this guide walks you through disconnecting and removing that user.

### Which kind of connection do you have?

* **Supabase (signed in with Supabase).** Whalesync created a database user named `whalesync_service_account_[ID]`. Complete all three steps below to remove it.
* **Postgres or Supabase connection string.** You gave Whalesync a connection string for a user you created yourself, so there is no extra `whalesync_service_account_[ID]` user. Complete **Step 1**, then rotate or delete that database user on your side. You can stop after Step 1.

If you aren't sure which you have, open the Supabase **SQL Editor** and run:

```sql
select rolname from pg_roles where rolname like 'whalesync_service_account_%';
```

If it returns a row, you have the first kind and should complete all three steps. Copy the `rolname` returned by the query as it will be used in **Step 3**.

### Step 1: Stop and delete your syncs

In Whalesync, stop and delete every sync that uses this Supabase project. Once no sync uses it, Whalesync no longer reads from or writes to your database.

### Step 2: Revoke Whalesync's access in Supabase

In the Supabase dashboard, remove Whalesync's authorization so its access can't be reused:

1. Go to your **Organization settings**
2. Open **OAuth Apps** (sometimes shown under **Integrations** or **Apps**)
3. Find **Whalesync** and click **Revoke**

{% hint style="info" %}
The exact labels move around in Supabase's dashboard. You're looking for the list of authorized third-party apps.
{% endhint %}

### Step 3: Remove the Whalesync database user

In the Supabase dashboard, open the project that was connected to Whalesync, then open the **SQL Editor** from the left sidebar.

The `whalesync_service_account_[ID]` user is managed by the Whalesync integration, so a plain `drop role` is denied with `42501: permission denied`. Supabase's supported way to remove it is to first hand the user over to your `postgres` role, then drop it.

Run these statements one at a time, replacing `<role>` with the exact user name and keeping the double quotes:

```sql
-- give your postgres role control of the user
grant "<role>" to postgres;

-- move anything it owns to postgres (usually nothing) and clear its access
reassign owned by "<role>" to postgres;
drop owned by "<role>";

-- remove the user
drop role "<role>";
```

Run the `select` from the top of this guide again to confirm the user is gone. It should return no rows.


# Why do I need an ID column?

Details on why an ID column is required in Supabase for two-way sync

To enable two-way sync between Supabase and your other apps, Whalesync needs a way to uniquely identify each record in your Supabase database.

If your table already has a unique primary key, Whalesync will use it.

If not, Whalesync will automatically add a whalesync\_postgres\_id column to ensure each record can be tracked reliably.

<figure><img src="/files/3IowpEKyLZg8zTpxieXl" alt=""><figcaption><p>What the automatically added "whalesync_postgres_id" column looks like in Supabase</p></figcaption></figure>

Alternatively, if you'd prefer to add your unique ID field manually, you can follow these steps:

{% content-ref url="/pages/kmoit3oru7EZjPKo3YS3" %}
[Adding default values to primary keys](/connectors/supabase/adding-default-values-to-primary-keys)
{% endcontent-ref %}


# How to enable webhooks

Sync your Supabase data faster with Database Webhooks!

## What do webhooks do?

Webhooks are an optional feature of Supabase that Whalesync can use to speed up syncing of your data out of Supabase. When webhooks are enabled, Supabase will ping Whalesync whenever data is created, updated, or deleted in your database. This can speed up syncing because we don't have to check periodically for changes.

## How do I enable them?

1. Click on the Integrations tab when your project is selected in Supabase:

<figure><img src="/files/IJL6LOx6RkFgwEjcXHEx" alt="" width="199"><figcaption><p>Click the Integrations tab</p></figcaption></figure>

2. Search for "webhooks" and click on Database Webhooks

<figure><img src="/files/eFelcMQMtLW3MkTJ21j3" alt=""><figcaption><p>Find the Data Webhooks integration</p></figcaption></figure>

3. Click "Enable webhooks"

<figure><img src="/files/qOnugUNqfT4WBeZsdSFI" alt=""><figcaption><p>Enable webhooks</p></figcaption></figure>

4. Whalesync will automatically detect that webhooks have been enabled within 10 minutes, and will create them automatically.


# SQL scripts

See [SQL scripts](/connectors/postgres/sql-scripts) in the Postgres section.


# Primary key snippets

See [Primary key snippets](/connectors/postgres/primary-key-snippets) in the Postgres section.


# Foreign key snippets

See [Foreign key snippets](/connectors/postgres/foreign-key-snippets) in the Postgres section.


# Terminology

See [Terminology](/connectors/postgres/terminology) in the Postgres section.


# Multiple foreign keys in a single field

See [Multiple foreign keys in a single field](/connectors/postgres/multiple-foreign-keys-in-a-single-field) in the Postgres section.


# How to sync Postgres views

See [How to sync Postgres views](/connectors/postgres/how-to-sync-postgres-views) in the Postgres section.


# Webflow

## Webflow Connector Guide

This guide provides an overview of how to connect Whalesync to Webflow and answers common questions.

### Connecting to Webflow

To connect Whalesync to your Webflow account, we use OAuth. This is a secure, standard way for you to grant Whalesync access without sharing your password.

When you set up Webflow in Whalesync, you'll be redirected to Webflow's website. You'll be asked to log in to your Webflow account and then approve the connection to Whalesync. You'll then choose which workspaces or individual sites you'd like to give access to. Once you approve, you'll be sent back to Whalesync to continue your setup.

### Syncing Data

Whalesync treats your Webflow **Sites** as "bases" and your **Collections** as "tables". This allows you to sync data between your Webflow CMS and other apps.

Whalesync can sync several types of data from Webflow:

* **CMS Data**: Sync items from your Webflow CMS Collections.
* **Users**: If you use Webflow Memberships, you can sync your user accounts.
* **Form Submissions**: Data from your Webflow forms can be synced to other tools for analysis or processing.

A special feature of the Webflow connector is the **"Webflow Status"** field. When you map a Webflow table, Whalesync creates this field. It lets you control whether a CMS item is "Published", "Draft", or "Archived".

{% content-ref url="/pages/zjLUZ70HfNj2Oz1iFyW2" %}
[Webflow status field](/connectors/webflow/webflow-status-field)
{% endcontent-ref %}

#### Localized Sites

If your Webflow site uses Webflow Localization, Whalesync syncs each locale as its own table. You'll see your collections show up once per locale, with the locale tag in brackets (e.g. `Blog Posts (FR-FR)`). Note that creating a record in the primary collection creates it in every locale, but field edits are never copied between locales.

{% content-ref url="/pages/Tt3heGwKsYWKzFrK0WCz" %}
[Webflow localization](/connectors/webflow/webflow-localization)
{% endcontent-ref %}

#### Automatic Table and Field Creation

Whalesync can automatically create tables and fields in Webflow to match the structure of the other app you're syncing with.

### Things to Keep in Mind

#### **Publishing Your Site**

Any changes you make to your Webflow data through Whalesync (like creating a new CMS item or updating an existing one) will not be live on your website until you **publish** your site in Webflow. While you can change an item's status to "Published" using the "Webflow Status" field, the final step is always to go to your Webflow dashboard and publish the site to make the changes public.

Whalesync requires you to republish your Webflow site any time you make a change to the CMS structure (eg. add a new field to a collection) in order for syncing to work.

Webflow sites need to be published to all domains otherwise Webflow rejects API calls (aka sync updates).

![](/files/mK3EeXN8tFpjVSxsHY2P)

#### **Primary Field**

In Webflow, the primary field for a Collection is usually the `Name` field. Webflow requires this field to always have a non-empty value, so it's important to have this mapped correctly for reliable syncing. This is also the value that's used to display records in the Whalesync UI.

#### Multi-reference fields

Whalesync supports multi-reference fields out of the box! See the guide below to ensure this is configured correctly:

{% content-ref url="/pages/ocVKxSMliPmoS7zWH2J6" %}
[Reference fields](/features/additional-features/reference-fields)
{% endcontent-ref %}

#### Publishing Schedule Limitations

When Whalesync updates your Webflow CMS items (whether creating new items or modifying existing ones), any publishing schedules configured for those items will be automatically cleared. Webflow schedules are for a specific version of the item content, so any change to that content invalidates the schedule. To maintain your publishing schedule, you'll need to manually reconfigure the publishing schedule in the Webflow Designer.

## Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🎨 Color</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📅 Date/Time</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>✉️ Email</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 File</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖼️ Image</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🆔 Item ID</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🔗 Link</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖼️ Multi-image</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Multi-Reference</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔽 Option</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📞 Phone</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Plain text - single line</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📝 Plain text - multiple line</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🖇️ Reference</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📰 Rich text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Switch</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📹 Video link</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>

### Synthetic Fields

Whalesync adds some special fields to your Webflow tables. These fields are not present in your Webflow database but are available to map in your sync.

| Field Name        | Explanation                                                    | Writable  |
| ----------------- | -------------------------------------------------------------- | --------- |
| Webflow Status    | Controls the state of a CMS item (Active, Draft, or Archived). | Writable  |
| Webflow Record ID | The unique identifier for a record from Webflow's system.      | Read-only |
| Created On        | The timestamp for when a record was created in Webflow.        | Read-only |
| Updated On        | The timestamp for when a record was last updated in Webflow.   | Read-only |

###


# Supported fields - (AT x WF)

All the field types you can use with Whalesync

<table><thead><tr><th width="191.40442229107452">Field Type</th><th width="183.33892049326292">Airtable Name</th><th width="175.6713265499693">Webflow Name</th><th width="150">Status<select><option value="d62d5e1851844c7ca9b1f982f79b46fd" label="✅ Supported" color="blue"></option><option value="278af0830314416a8f0071bd1ff38507" label="✖️ Not Yet" color="blue"></option></select></th></tr></thead><tbody><tr><td>📝 󠁁Short text</td><td>Single line text</td><td>Plain text</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📝 Long text</td><td>Long text</td><td>Plain text</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>☑️ Checkbox</td><td>Checkbox</td><td>Switch</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>⬇️ Single select</td><td>Single select</td><td>Option</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📅 Date</td><td>Date</td><td>Date/Time</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>✉️ Email</td><td>Email</td><td>Email</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>🔗 URL</td><td>URL</td><td>Link</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>#️⃣ Number</td><td>Number</td><td>Number</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>🖇️ Linked records</td><td>Linked to another record</td><td>Reference</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>🖇️ Multi-reference</td><td>Link to another record - multiple</td><td>Multi-reference</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📂 Attachment</td><td>Attachment</td><td>File</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>🖼️ Image</td><td>Attachment</td><td>Image</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>🖼️ Multi-image</td><td>Attachment</td><td>Multi-image</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📰 Rich text</td><td>Long text - rich text</td><td>Rich text</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📞 Phone number</td><td>Phone number</td><td>Phone</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>💱 Currency</td><td>Currency</td><td>Number</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>➗ Percent</td><td>Percent</td><td>Number</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>📊 Formula</td><td>Formula</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>👀 Lookup</td><td>Lookup</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Duration</td><td>Duration</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Rating</td><td>Rating</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Count</td><td>Count</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Autonumber</td><td>Autonumber</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Barcode</td><td>Barcode</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Rollup</td><td>Rollup</td><td>-</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Video link</td><td>-</td><td>Video link</td><td><span data-option="d62d5e1851844c7ca9b1f982f79b46fd">✅ Supported</span></td></tr><tr><td>Multi-select</td><td>Multi-select</td><td>-</td><td><span data-option="278af0830314416a8f0071bd1ff38507">✖️ Not Yet</span></td></tr><tr><td>Collaborator</td><td>Collaborator</td><td>-</td><td><span data-option="278af0830314416a8f0071bd1ff38507">✖️ Not Yet</span></td></tr><tr><td>Created by</td><td>Created by</td><td>-</td><td><span data-option="278af0830314416a8f0071bd1ff38507">✖️ Not Yet</span></td></tr><tr><td>Button</td><td>Button</td><td>-</td><td><span data-option="278af0830314416a8f0071bd1ff38507">✖️ Not Yet</span></td></tr></tbody></table>


# Webflow Memberships sync

Sync users from Webflow into other apps

<figure><img src="/files/aD1MgighiyQ1P3fCPmdS" alt=""><figcaption><p>Whalesync supports syncing members through the "User accounts" table.</p></figcaption></figure>

### Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="a5cd90d6db5a416a882aa7a988f0c81a" label="✅ Supported" color="blue"></option><option value="342517587230452ca3e3f62868fcdc45" label="➡️ Supported (1-way)" color="blue"></option><option value="568ec9d3184541c0a36f9ef0c2c66ce1" label="✅ Supported (Write-Once)" color="blue"></option><option value="ae9d6cd5a7bc48a2ac8067e50a4b4641" label="✖️ Not Yet" color="blue"></option></select></th></tr></thead><tbody><tr><td>Access groups</td><td><span data-option="ae9d6cd5a7bc48a2ac8067e50a4b4641">✖️ Not Yet</span></td></tr><tr><td>☑️ Accept privacy</td><td><span data-option="a5cd90d6db5a416a882aa7a988f0c81a">✅ Supported</span></td></tr><tr><td>☑️ Accept communications</td><td><span data-option="a5cd90d6db5a416a882aa7a988f0c81a">✅ Supported</span></td></tr><tr><td>✉️ Email</td><td><span data-option="568ec9d3184541c0a36f9ef0c2c66ce1">✅ Supported (Write-Once)</span></td></tr><tr><td>☑️ Email Verified</td><td><span data-option="342517587230452ca3e3f62868fcdc45">➡️ Supported (1-way)</span></td></tr><tr><td>📅 Last Login</td><td><span data-option="342517587230452ca3e3f62868fcdc45">➡️ Supported (1-way)</span></td></tr><tr><td>📝 Name</td><td><span data-option="a5cd90d6db5a416a882aa7a988f0c81a">✅ Supported</span></td></tr><tr><td>🔽 Status</td><td><span data-option="342517587230452ca3e3f62868fcdc45">➡️ Supported (1-way)</span></td></tr><tr><td>🆔 Webflow Record ID</td><td><span data-option="342517587230452ca3e3f62868fcdc45">➡️ Supported (1-way)</span></td></tr></tbody></table>

Webflow's [Memberships feature](https://webflow.com/memberships) lets you manage users in your Webflow site.

### Not Yet Supported

Webflow Memberships is a relatively new feature with a relatively new API. Due to this, there are certain features we cannot support yet.

1. We do not yet support custom fields.
2. We do not yet support mapping the Access Groups table.

### Creating Users

Whalesync allows you to create new users in Webflow Memberships from other apps (e.g. Airtable). Note - the email field is a "write-once" field. See our docs on creating users for more details:

{% content-ref url="/pages/jfPPLfKhxnLSzCyFRP74" %}
[Creating users via Whalesync](/features/additional-features/creating-users-via-whalesync)
{% endcontent-ref %}

### Template

If you're syncing Webflow users with Airtable, you can copy our free Airtable template which includes all available fields:

{% embed url="<https://airtable.com/shrVADkHQUCcIWSRv>" %}


# Webflow status field

Control the status of a Webflow item via a field in other apps

### About Webflow Status field

Webflow lets you control the status of an item by marking it as either Published, Draft, or Archived. With our Webflow Status field sync, you can now control that state from apps like Airtable or Notion.

For example, if you manage your blog content in Notion, you can now control whether those blog posts are live or in draft from within Notion.

{% hint style="info" %}
Using the Webflow Status field may reduce sync speed by a few seconds per record.
{% endhint %}

### How to set up the Webflow Status field

1. Add a single-select field to your Airtable or Notion table and title it "Webflow Status"
2. Make sure it has *exactly* these three options:
   1. "Archived"
   2. "Draft"
   3. "Active"
3. In Whalesync, map that field to Webflow's "Webflow Status" field
   1. If adding this field to an existing base, make sure to initialize the data from Webflow (see screenshot below)

<figure><img src="/files/ZzerzaBlrEXxMZHLffat" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/kUrTpFLFHgvEpI4nFiYj" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Airtable lets you set a default value for single select fields so you can, for example, set a default value of 'Draft'.\
\
\*Note - if no default value is set and the value is empty in this field, the behavior will default to 'Published'.
{% endhint %}

### "Active" vs. "Published"

In Webflow, you can make an item "Published" as well as "Staged for Publish". When an item is "Staged for Publish" it means it will become published next time you publish your Webflow site.

With our Webflow Status field, both "Published" and "Staged for Publish" are captured by the option "Active".

### Mini-demo

<figure><img src="/files/gnDpQqshceLkL8VvVjZO" alt=""><figcaption><p>Demo using the Webflow status field</p></figcaption></figure>

### Limitations

#### Status field in conjunction with reference fields

One limitation of Webflow CMS collection items is that a **published** Webflow item cannot reference a **draft** Webflow item in a reference field. Unfortunately this is a Webflow restriction.

For example, the following will result in an error from the Webflow API:

1. Create two collections in Webflow. For this example, let's call them *People* and *Teams*
2. Create a reference field on the *People* collection that points to *Teams*
3. Create an item "Marketing" in the *Teams* collection and set it to "published"
4. Create an item "Sally Smith" in the *People* collection, add a reference to the "Marketing" item in the reference field, and set "Sally Smith" to "published"
5. Create a sync in Whalesync using the two Webflow collections and sync it to another app (such as Airtable)
6. In Airtable, set the Webflow Status field on the "Marketing" item to "Draft"

This will result in an error that will show up on the Whalesync Issues page. Webflow will reject the attempt to set the "Marketing" item to "Draft" because the **published** person "Sally Smith" is referencing the item. Unfortunately Whalesync does not have a workaround for this.

### Field Validation and Error Handling

#### Enforced Status Options

Whalesync now strictly enforces that the Webflow Status field must contain exactly one of these three values:

* **Archived**
* **Draft**
* **Active**

If you use any other value in your status field, you will receive an error message like:

```
Data "Pending" isn't one of the valid values: [Draft, Active, Archived].
```

This validation helps ensure consistency and prevents sync errors.

#### "Published" Option Support

We understand that "Published" might feel like a more natural option name for many users, so Whalesync accepts "Published" as a valid value to make your setup easier. However, here's what happens when you use it:

* Whalesync will automatically sync "Published" values back as "Active" to maintain consistency with our three-option system
* This ensures your data stays aligned with the standard status options (Draft, Active, Archived)
* You can use "Published" if it makes more sense for your workflow, just be aware that it will appear as "Active" when synced back

This flexibility allows you to use the terminology that feels most natural while keeping the system consistent.


# Webflow localization

Sync localized Webflow CMS content across every locale on your site

{% embed url="<https://www.loom.com/share/27af9bc5964149f2a26fc6b0f3db78a3>" %}

If your Webflow site uses [Webflow Localization](https://webflow.com/localization) to publish CMS content in more than one language, Whalesync can sync each locale.

### How localized collections appear in Whalesync

When your Webflow site has secondary locales, each localized CMS collection shows up in Whalesync more than once:

* The **primary locale** keeps the collection's normal name (e.g. `Blog Posts`).
* Each **secondary locale** appears as a separate table with the locale tag in brackets (e.g. `Blog Posts (FR-FR)`, `Blog Posts (DE-DE)`).

Each of these is a regular Whalesync table. You map fields, turn on two-way sync, filter, and otherwise work with a locale table exactly like any other Webflow table: point it at a table in Airtable, Notion, Google Sheets, etc., and it syncs normally.

{% hint style="info" %}
The locale shown in brackets is Webflow's [BCP-47 locale tag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language), uppercased: `FR-FR` for French (France), `EN-GB` for English (United Kingdom), and so on. This keeps regional variants of the same language unambiguous.
{% endhint %}

### How records are created across locales

Webflow doesn't let you add a single locale to an existing CMS item through its API. Every locale variant of an item has to exist from the moment the item is created. Because of that:

* **Creating a record in the primary-locale table also creates it in every other locale.** When a new record syncs into your primary collection (e.g. `Blog Posts`), Whalesync automatically materializes the matching item in all of your secondary-locale collections at the same time. You don't need to create the record separately in each locale.

This means a brand-new item starts life in every locale, ready for you to fill in translated content per locale.

### Field edits are never synced between locales

After an item exists, **Whalesync never copies field edits from one locale to another.** Each locale table syncs independently:

* Editing a field in `Blog Posts` updates only the primary-locale content in Webflow.
* Editing a field in `Blog Posts (FR-FR)` updates only the French content.

This is intentional: localized content is supposed to differ per locale, so Whalesync keeps each locale's values isolated rather than overwriting one language's translation with another's. If you want the same value in every locale, set it in each locale's table (or in the source records that map to each locale table).

{% hint style="warning" %}
Because edits don't propagate across locales, the **primary-locale value is&#x20;*****not*****&#x20;a default** for the other locales. A newly created item's secondary-locale fields start out as Webflow's own copy of the primary content, but from then on each locale is edited independently.
{% endhint %}

### Things to keep in mind

* **Republish to go live.** As with any Webflow change made through Whalesync, localized edits won't appear on your site until you publish it in Webflow. See [Webflow](/connectors/webflow) for more on publishing.
* **New locales.** If you add a secondary locale in Webflow after setting up your sync, re-fetch the schema (edit your base) in Whalesync so the new locale table shows up.
* **Don't see the locale tables?** Make sure your Webflow site actually has secondary locales configured and that your connection is reauthorized after enabling Localization. If they still don't appear, reach out to support.
* **Newly created items not being added to other locales?** Webflow localization is tricky and sometimes you don't want Whalesync to automatically create items in each locale, whereas sometimes you do. If you want your items created in all locales, make sure to turn on '*Create new items in all locales'* in your sync settings.


# Wix CMS

## Wix CMS Connector Guide

This guide provides an overview of how to connect Whalesync to Wix CMS (also called Content Manager).

If you're unsure whether you're using Wix's CMS, review Wix's overview: [About the CMS (Content Manager)](https://support.wix.com/en/article/cms-content-management-system-an-overview). The CMS is for managing structured content in collections and powering dynamic pages. This is distinct from other Wix features like Wix Blog, Wix Forms, Wix Stores, Wix Bookings, Wix Events, or other Wix data sources.

### Connecting to Wix CMS

To connect your Wix CMS account to Whalesync, you'll authenticate using OAuth. This securely grants Whalesync access without sharing your password.

When you connect, you'll be redirected to Wix to approve the connection. As part of authorization, you must choose the specific Wix site you want Whalesync to access. After approving access to that site, you'll be returned to Whalesync to continue setup.

### Compatible fields

Whalesync does not provide full support for all fields in Wix CMS. If you need anything that is missing, please [reach out and let us know](/resources/support) to inform our planning.

| Field                     | Status                        | Notes                           |
| ------------------------- | ----------------------------- | ------------------------------- |
| Text                      | ✅ Fully supported             |                                 |
| Number                    | ✅ Fully supported             |                                 |
| Date                      | ✅ Fully supported             |                                 |
| Time                      | ✅ Fully supported             |                                 |
| Boolean                   | ✅ Fully supported             |                                 |
| Image                     | ✅ Fully supported             |                                 |
| URL                       | ✅ Fully supported             |                                 |
| Document                  | ✅ Fully supported             |                                 |
| Tags                      | ✅ Fully supported             |                                 |
| Color                     | ✅ Fully supported             |                                 |
| Reference                 | ✅ Fully supported             |                                 |
| Multi-reference           | ✅ Fully supported             |                                 |
| Javascript object & array | ✅ Fully supported             |                                 |
| Rich content              | ⚠️ Supported with limitations | Does not support embedded media |
| Media Gallery             | ➡️ Supported (1-Way)          | Read-only                       |
| Address                   | ➡️ Supported (1-Way)          | Read-only                       |
| Rich text                 | ✖️ Not supported              |                                 |
| Audio                     | ✖️ Not supported              |                                 |
| Video                     | ✖️ Not supported              |                                 |
| Multiple documents        | ✖️ Not supported              |                                 |

### Item Visibility

Wix CMS collections have a "Control item visibility" feature that adds a **Status** field to each item, which can be set to "Visible" or "Hidden." This feature is enabled by default for collections created after November 4th, 2025, and can be manually enabled for older collections.

Items marked as "Hidden" in Wix are **not accessible via the Wix API**, which means they will not be synced by Whalesync. This is a Wix platform limitation — there is no way to query hidden items through the API for regular CMS collections.

**If you notice items missing from your sync**, check the Status field in your Wix collection to confirm the items are set to "Visible."

{% hint style="warning" %}
If you are using the built-in visibility feature to manage draft or unpublished content, those items will not sync. Instead, we recommend creating a custom boolean field (e.g., "isPublished") in your collection to control your publishing workflow. Custom fields are always accessible via the API and will sync normally regardless of their value.
{% endhint %}

### Additional Fields

Whalesync adds special fields that are available to map in your sync but are not visible in Wix.

| Field Name    | Explanation                                   | Writable |
| ------------- | --------------------------------------------- | -------- |
| Wix Record ID | The unique identifier for an item in Wix CMS. | No       |


# WordPress.org

## Supported Versions

Whalesync requires Wordpress version **5.6** or greater.

### Supported Hosting Platforms

Whalesync has been tested against the following Wordpress hosting platforms:

* [WP Engine](https://wpengine.com/)
* [BlueHost](https://www.bluehost.com/)

## Recommended Settings

* We recommend that the user you generate the Application Password from for Whalesync has the role "Administrator". The minimum required role is "Editor".
* We recommend making sure your Wordpress Permalinks are not set to "Plain":

<figure><img src="/files/nHDsgEntyauR4gRBCpxt" alt=""><figcaption></figcaption></figure>

## Supported Types

<table><thead><tr><th width="358.5">Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option><option value="3ed1eb655ce94da49e887be21197ec27" label="🔜 Coming Soon" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>Posts</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Custom Posts</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Pages</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Categories</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Media</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Tags</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Users</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

## Supported Fields

<table><thead><tr><th width="358.5">Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🔽 Categories</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Content</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ Custom Fields</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 Excerpt</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Featured Media</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f5c3">🗃️</span> Format</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f517">🔗</span> Link</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🕠 Published Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><a href="https://emojipedia.org/link/">🔗</a> Slug</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ Status</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f51d">🔝</span> Sticky</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><a href="https://emojipedia.org/label/">🏷️</a> Tag</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📄 Title</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🫂 Author</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

## Supported Blocks for Content

<table><thead><tr><th>Block</th><th>Status<select><option value="f15a9d7970f64475a1e42cabfeed8b70" label="✅ Supported" color="blue"></option><option value="a59365fcbbfa4ad186d76ffc8461936e" label="✖️ Not Yet" color="blue"></option></select></th></tr></thead><tbody><tr><td>🎧 Audio</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>📍 Bullet List</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="2328">⌨️</span> Code</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Gallery</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>📄 Heading (1-6)</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Image</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>📂 Media &#x26; Text</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>#️⃣ Numbered List</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>💬 Quote</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>📄 Verse</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>📹 Video</td><td><span data-option="f15a9d7970f64475a1e42cabfeed8b70">✅ Supported</span></td></tr><tr><td>🏛️ Classic</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Cover</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td>📂 File</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td>⏩ Preformatted</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td>💬 Pullquote</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td>📑 Table</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f3b9">🎹</span> Shortcode</td><td><span data-option="a59365fcbbfa4ad186d76ffc8461936e">✖️ Not Yet</span></td></tr></tbody></table>

## WordPress Multisite

Whalesync supports WordPress Multisite installations. Each site in your network is treated as its own independent instance, so **you need to create one base per site** you want to sync.

The URL you provide when connecting determines which site Whalesync will sync with:

| Site      | URL Example                            |
| --------- | -------------------------------------- |
| Main site | `https://whalesync-wp.com/`            |
| Subsite   | `https://whalesync-wp.com/sub-site-1/` |

If you want to sync multiple sites in your network, create a separate base for each one using the appropriate URL.

## Things to keep in mind

{% hint style="info" %}
Whalesync works with WordPress version 5.6 and above
{% endhint %}

{% hint style="info" %}
We recommend using a backup/restore plugin if connecting WordPress to a 2-way sync tool like Whalesync :point\_down:
{% endhint %}

{% embed url="<https://wordpress.com/support/restore/>" %}


# Quick Start Guide: WordPress.org

Tips to help you get started syncing WordPress

### 1) Authorize with the *right* user email and application password

See these docs :point\_down:

{% content-ref url="/pages/doYDwhpx0Hm3LRGSjood" %}
[Authorize WordPress.org](/connectors/wordpress.org/authorize-wordpress.org)
{% endcontent-ref %}

### 2) Start with our template

If syncing WordPress and Airtable, we recommend starting with our template which has all the tables and fields we support.

{% embed url="<https://www.whalesync.com/template-packs/wordpress-blog-3>" %}

###

### 4) Create tables for Categories and Tags

Categories and Tags must exist as linked records on your Posts. Once again, if you're unsure about how this all works you can just copy our [Airtable template](https://www.whalesync.com/template-packs/wordpress-blog-3).

See the below docs for further explanation of supporting tables :point\_down:

{% content-ref url="/pages/ZJARjK8GriAtRLb8ld86" %}
[Supporting tables](/connectors/wordpress.org/supporting-tables)
{% endcontent-ref %}

<figure><img src="/files/WxJLwpcyPgvuCEeCweLI" alt=""><figcaption><p>Categories as a linked record on the Posts table</p></figcaption></figure>

### 5) Toggle "show in REST API" to use Advanced Custom Fields (ACF)

Whalesync lets you sync Custom Posts and Custom Fields thru ACF using these steps :point\_down:

{% content-ref url="/pages/Lp4vgebHicvTR2B32r05" %}
[Advanced Custom Fields (ACF)](/connectors/wordpress.org/advanced-custom-fields-acf)
{% endcontent-ref %}

### 6) Monitor usage graphs

Once you turn sync on, we recommend monitoring your WordPress.org host (e.g. WP Engine or Kinsta) for the first few hours. These hosts typically have limits for billable visits and bandwidth that are worth monitoring.

### 7) Watch our video tutorial

{% embed url="<https://www.youtube.com/watch?v=q-6AwuiInFA>" %}


# Authorize WordPress.org

### How to get your user email

1. Click Users > Profile
2. Scroll down to `Email`
3. Copy your email address

<figure><img src="/files/FZLSwrkRUXPIbp6B4s8h" alt=""><figcaption></figcaption></figure>

### How to get your password

1. Click Users > Profile
2. Scroll down to `Application Passwords`
3. Enter an application password name
4. Press "Add New Application Password"
5. Copy your password

<figure><img src="/files/p1TCP1ZAnnY9nQ2047LJ" alt=""><figcaption></figcaption></figure>

### Which user role do I need?

The user you connect with needs at least the **Editor** role. When you connect, Whalesync checks that the user can edit posts, so an Author, Contributor, or Subscriber account will fail with a "not allowed to edit" error even when the email and application password are correct.

### How to find your domain name

Simply enter the domain of your WordPress site. For example:

<mark style="color:purple;background-color:yellow;">**<https://whalesyncseo.wpengine.com>**</mark>

Some WordPress hosts don't let Whalesync reach your data through your site's main domain. In that case, enter the domain where your WordPress dashboard lives—but **without** the `/wp-admin` path. For example, if your dashboard is at `https://blog.example.com/wp-admin`, enter `https://blog.example.com` (not your public homepage at `https://example.com`).

### "You are not allowed to edit posts"

This error means your login worked but the user does not have permission to edit content. Two things to check:

1. Give the connecting user at least the **Editor** role.
2. Make sure the WordPress URL you entered is your dashboard site URL. It can differ from your public site URL.


# Advanced Custom Fields (ACF)

How to use Whalesync's WordPress connector with ACF

Whalesync supports syncing **Custom Post Types** and **Custom Fields** with ACF.

## Using ACF Custom Fields

To use ACF Custom Fields, you'll need to toggle the setting "show in REST API" on for each Field Group you want to use:

<figure><img src="/files/QqQ4nACzrGtHjR1sQr3B" alt=""><figcaption></figcaption></figure>

Because of how Wordpress returns metadata for ACF fields through the API, you also need to have at least one rule in the "Location Rules" that checks for the Post Types you want the field to be a part of. For example, if you want to sync your ACF fields with the Posts table, you'll need a check for "Post Type is equal to Post".

<figure><img src="/files/15ok2zRqt99ulsUzlcT4" alt=""><figcaption></figcaption></figure>

If you use more complex logic than this already, and don't want to always show the ACF fields in a group on a specific table, you can add a condition that will never match along with the check in a new rule group. This will still allow Whalesync to pick up the field, but won't affect how your fields are shown in the Wordpress UI.

<figure><img src="/files/dz3yzBH3NlGHv3VkWWGk" alt=""><figcaption></figcaption></figure>

## Supported Field Types

<table><thead><tr><th width="358.5">Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option><option value="3ed1eb655ce94da49e887be21197ec27" label="🔜 Coming Soon" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>👤 Text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔽 Text Area</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🗃️ Range</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>✉️ Email</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 URL</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Password</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td><a href="https://emojipedia.org/framed-picture/">🖼️</a> Image</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>👤 Author</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>


# How to sync images

A quick demo for syncing images into WordPress posts/pages

{% embed url="<https://www.loom.com/share/2cbc66c7701144c79866f6195e10fd30?sid=4f45a60f-52fd-49ce-875d-11220165dc9a>" %}

**TL;DR**

1. Create a "Media" table in Airtable
2. In the Airtable table you want to have an image field (e.g. Posts), create a linked record field to the Media table
3. In your ACF custom image field name the field "image\_fk\_media"
4. Now you can map the linked record field in Airtable to the ACF custom field in WordPress

<figure><img src="/files/RBjDZFVtx4k0HlilUQg1" alt=""><figcaption></figcaption></figure>


# Supporting tables

How to set up all the right tables when syncing WordPress

## Overview

There are four tables every WordPress instance has:

<table><thead><tr><th>Name</th><th>Type<select><option value="2cf6fc5309b64ecd8815745df5fcdaaa" label="Main" color="blue"></option><option value="9b401e0fa5c04bda85fd3486ce2cb75c" label="Supporting" color="blue"></option></select></th></tr></thead><tbody><tr><td>Pages</td><td><span data-option="2cf6fc5309b64ecd8815745df5fcdaaa">Main</span></td></tr><tr><td>Posts</td><td><span data-option="2cf6fc5309b64ecd8815745df5fcdaaa">Main</span></td></tr><tr><td>Categories</td><td><span data-option="9b401e0fa5c04bda85fd3486ce2cb75c">Supporting</span></td></tr><tr><td>Tags</td><td><span data-option="9b401e0fa5c04bda85fd3486ce2cb75c">Supporting</span></td></tr></tbody></table>

*(If you have Custom Posts enabled, you will see more tables for each Custom Post type)*

The star of your site are the Pages and Posts - everything else is there to support them.

{% hint style="info" %}
**Tip:** We highly recommend that you map Categories and Tags in Whalesync!\
\
You can use our [Airtable template](https://www.whalesync.com/template-packs/wordpress-blog-3) which has these tables pre-configured.
{% endhint %}

## Supporting Tables

### Categories and Tags

Like the Users table, if you want to sync WordPress Categories and Tags, you'll need to set up supporting tables.

{% hint style="info" %}
**Tip:** Make sure "allow linking to multiple records" is toggled so you can link multiple categories and tags.
{% endhint %}

<figure><img src="/files/WxJLwpcyPgvuCEeCweLI" alt=""><figcaption></figcaption></figure>

### Users

The Users table lists all the users of your site. Tables like Pages and Posts all have a field called Author that can point to a user in this list.

{% hint style="warning" %}
**Note:** Whalesync does not support mapping the Users table at this time. You will have to manage users in the WordPress UI.
{% endhint %}

### Media

The Media table contains media like images, audio, and videos that you've uploaded to your Wordpress site. Posts, Pages, and custom post types have a field called Featured Image that can point to a media item in this list.

{% hint style="warning" %}
**Note:** Whalesync does not support mapping the Media table at this time. Compatible media will be automatically uploaded into the Wordpress Media Library during the sync.
{% endhint %}


# Syncing custom taxonomies

How to sync WordPress custom taxonomies with Whalesync

Whalesync automatically discovers the two built-in WordPress taxonomies — **Categories** and **Tags** — and surfaces them as their own tables you can map (see [Supporting tables](/connectors/wordpress.org/supporting-tables)).

{% hint style="warning" %}
**Custom taxonomies are not discovered as their own tables.** A custom taxonomy you've registered (for example `site-category`) won't appear as a separate mappable table, and refreshing the schema or reconnecting the connector won't change that. You can still sync to it using the steps below.
{% endhint %}

## How to sync to a custom taxonomy

WordPress represents a taxonomy assignment on a post as the taxonomy term's numeric **ID**, not its name. So to sync a custom taxonomy, you map a field containing the term ID(s) to one of these columns on your Posts, Pages, or custom post type table:

* The **native taxonomy field** WordPress adds to the post type when the taxonomy is registered with **Show in REST API** enabled and associated with that post type.
* An [**ACF**](/connectors/wordpress.org/advanced-custom-fields-acf) **field of type "Taxonomy"**, if you've set one up.

Both accept the numeric term ID and check off the matching term on the post.

### 1. Find the term IDs

You can find a term's ID either way:

* List the taxonomy's terms at `https://your-site.com/wp-json/wp/v2/<taxonomy>` and read each term's `id`.
* Or open the term's edit page in WordPress admin — the ID is the `tag_ID` value in the URL (e.g. `.../term.php?taxonomy=site-category&tag_ID=22`).

### 2. Get the IDs into your source

Because WordPress wants the ID and not the label, the cleanest setup in Airtable is a small lookup table:

1. Create a table that maps each term's **name** to its **WordPress ID**.
2. On the table you're syncing, add a "Link to another record" field pointing at that lookup table, plus a Lookup field that pulls in the ID.
3. Sync the Lookup field. This way you pick terms by name in Airtable instead of memorizing IDs.

### 3. Map it in Whalesync

Map that ID field to the taxonomy column on the matching post type table, and run your sync. The term will be assigned to the post the same way the built-in Categories field works.

{% hint style="info" %}
**Tip:** To assign more than one term to a record, use a field that outputs multiple IDs and toggle "allow linking to multiple records" so multiple values sync through.
{% endhint %}

{% hint style="warning" %}
**Seeing two columns for the same taxonomy?** If a taxonomy is both associated with a post type **and** exposed as an ACF field, Whalesync shows two similarly-named columns — the native one (named after the taxonomy, e.g. "Site Category") and the ACF one (named after its field name, e.g. "Acf Site Category"). Map only one of them, and make sure it's the one you intend — mapping the wrong column won't error, it just won't update the post.
{% endhint %}

## Notes

* **Terms must already exist in WordPress.** This assigns posts to existing terms by their ID — it does not create new terms in the taxonomy. Create the terms in WordPress first, and keep your lookup table up to date if you add more.
* **Permissions:** make sure the WordPress user Whalesync connects with is an **Editor** or **Admin** so it is allowed to assign terms.


# Tutorial

How to sync Airtable and WordPress to create programmatic SEO pages

{% embed url="<https://www.youtube.com/watch?v=q-6AwuiInFA>" %}


# WordPress status field

Control the status of a WordPress post via a field in other apps

### About WordPress Status field

* WordPress lets you control the status of a post by marking it as either Published, Draft, or Pending.
* With our WordPress Status field sync, you can now control that state from apps like Airtable or Notion.
* For example, if you manage your blog content in Notion, you can now control whether those blog posts are live or in draft from within Notion.

{% hint style="info" %}
If you want to choose when a row in Airtable or Notion is synced to Wordpress, you can also use the [Selective row-level sync](/features/additional-features/selective-sync) feature.
{% endhint %}

### How to set up the WordPress Status field

1. Add a single-select field to your Airtable or Notion table and title it "Status"
2. Make sure it has *exactly* these three options:
   1. "publish"
   2. "draft"
   3. "pending"
3. In Whalesync, map that field to WordPress' "Status" field

![](/files/MrWn8DjmJ2xfWFuR4qBk)

{% hint style="info" %}
Airtable lets you set a default value for single select fields so you can, for example, set a default value of 'Draft'
{% endhint %}


# REST API endpoints

The WordPress REST API endpoints Whalesync uses under the hood

## Overview

Whalesync talks to your site through the standard [WordPress REST API](https://developer.wordpress.org/rest-api/) (the `wp-json` endpoints). This page lists the specific endpoints we call and what each one is for. It's mostly here for the curious and for anyone debugging a connection at the network level — you don't need to know any of this to set up a sync.

Throughout, `{type}` is a post type slug (for example `posts`, `pages`, or a custom post type) and `{id}` is a record's ID.

## Endpoints by function

<table><thead><tr><th>Function</th><th width="140">Method</th><th>Path</th><th>Key query params</th></tr></thead><tbody><tr><td>Auth / connection probe</td><td>GET</td><td><code>wp/v2/posts</code></td><td><code>per_page=5&#x26;context=edit</code></td></tr><tr><td>Discover REST root</td><td>HEAD / GET</td><td>site root (reads <code>Link</code> header) → <code>wp-json/</code></td><td>—</td></tr><tr><td>List available post types (tables)</td><td>GET</td><td><code>wp/v2/types</code></td><td>—</td></tr><tr><td>Fetch a table's field schema</td><td>OPTIONS</td><td><code>wp/v2/{type}</code></td><td>—</td></tr><tr><td>Poll / list records</td><td>GET</td><td><code>wp/v2/{type}</code></td><td><code>per_page=100</code> + <code>page=n&#x26;orderby=id&#x26;order=asc</code> (or <code>offset=n</code>); <code>status=any</code></td></tr><tr><td>Get one record</td><td>GET</td><td><code>wp/v2/{type}/{id}</code></td><td><code>status=any</code></td></tr><tr><td>Create record (new row)</td><td>POST</td><td><code>wp/v2/{type}</code></td><td>—</td></tr><tr><td>Update record</td><td>PATCH</td><td><code>wp/v2/{type}/{id}</code></td><td>—</td></tr><tr><td>Delete record</td><td>DELETE</td><td><code>wp/v2/{type}/{id}</code></td><td><code>force=true</code></td></tr><tr><td>Upload media</td><td>POST</td><td><code>wp/v2/media</code></td><td>raw file body + <code>Content-Disposition</code></td></tr><tr><td>Get media</td><td>GET</td><td><code>wp/v2/media/{id}</code></td><td>—</td></tr></tbody></table>


# Previous connectors

Connectors we've supported in the past but no longer offer

## FAQ

### Why do we no longer offer these connectors?

Whalesync is a flexible tool and every API has its own challenges. When we launch a new connector, we don't always know the full extent of which kinds of sync pairs will be set up, what all of the use cases will be, the record sync volume, and speed requirements for those syncs.

Over time, we sometimes discover that a particular connector is not delivering a best-in-class experience. We hold ourselves to a high standard, so if we don't see a good path to improving the experience, we decide to retire a connector.

### If I have a sync with one of these connectors, will it keep working?

Yes, your existing syncs will stay active and will continue to run as they always have. However, because the connector is retired, future improvements, bug fixes, and support will be limited.

### If I'm using one of these connectors, do I need to migrate to another platform?

That's 100% up to you and depends on your situation. Your syncs will remain active and if they're working well for you, then that's great, no need to switch. However if they're not meeting your needs, please reach out to <support@whalesync.com> and we can recommend alternatives.

### If I'm on a yearly plan and I move my sync with a retired connector away from Whalesync, can I get a refund?

You can request a plan cancellation and get a refund for the remaining time on your subscription if your situation meets all of the following conditions:

* You're on a yearly subscription plan
* You have a sync with a retired connector
* You delete your syncs using the retired connector

Just reach out to <support@whalesync.com> and we'll be happy to help.

## Previous connectors

* [Bubble](/previous-connectors/bubble)
* [Close](/previous-connectors/close)
* [Copper](/previous-connectors/copper)
* [MS Dynamics CRM](/previous-connectors/ms-dynamics-crm)
* [Outreach](/previous-connectors/outreach)
* [Shopify](/previous-connectors/shopify)
* [Webflow E-commerce](/previous-connectors/webflow-e-commerce)
* [Zoho CRM](/previous-connectors/zoho-crm)


# Bubble

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Bubble

### Bubble API Changes <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

{% hint style="warning" %}
On April 6, 2023, Bubble [announced](https://bubble.io/blog/2023-pricing-updates/) pricing changes that affected their API, and on October 1, 2024, they migrated all users to new API pricing.

Due to Bubble's API limitations, **Whalesync will be slower to sync changes out of Bubble** and you will likely need to upgrade your Bubble plan to continue using Whalesync.

Whalesync uses polling to observe changes to records, which uses Bubble's "workload units". Bubble does not support webhooks which would reduce the need for polling. We are working with the Bubble team to find a good solution, but in the meantime, please be aware that Whalesync may use a significant amount of your workload units depending on your Bubble subscription.
{% endhint %}

### Supported Fields

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🖇️ Composite types</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🧑 Created by</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>🕠 Created date</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📅 Date</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📅 Date interval</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>📅 Date range</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>📍Geographic address</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>📂 Image/file</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🕠 Modified date</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>#️⃣ Number</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️⃣ Number interval</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>📝 Slug</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>📝 Text</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🫂 User</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>☑️ Yes/no</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr></tbody></table>

### Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

{% hint style="warning" %}
**Must enable data API**\
Bubble requires the Data API to be enabled for syncing to work. Follow the instructions below to enable it.
{% endhint %}

<figure><img src="/files/4Qu1WFUthkhJe8cDEjwt" alt=""><figcaption></figcaption></figure>

1. Go to Settings > API
2. Check the box for "Enable Data API"
3. Check the box for all tables you plan to sync

{% hint style="danger" %}
**Renaming schema, tables, or columns will break Whalesync mappings**\
If you rename a table or column, you'll need to remap the impacted table/column in Whalesync. Note - remapping an impacted table will lead to duplicates unless you reset your data as well.

If you need to rename a table in Bubble, we suggest making sure that every record has a unique identifier that can be matched on, then turn off the old sync and set up a new sync with [Record matching](/features/record-matching).
{% endhint %}

{% hint style="info" %}
**The email field for User "things" has a record sync delay if syncing with Airtable**\
Bubble has a special data table called User that they treat differently than other tables. Specifically, you need to send it a valid email address. When syncing Bubble with Airtable, this can cause problems since Airtable saves every keystroke.\
\
To avoid this issue, Whalesync defaults to a 30-second record sync delay. See [record sync delay](https://github.com/whalesync/docs/tree/main/previous-connectors/bubble/broken-reference/README.md) for more details.
{% endhint %}


# Authorize Bubble

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Authorize Bubble

In order to connect Bubble to Whalesync, you'll need two things:

* Your Bubble app API key
* Your Bubble app API URL

#### Setting up the Bubble Data API and getting your API key

In Bubble, go to Settings (1), then to the API tab (2). Check the box to enable the Data API (3).

<figure><img src="/files/cWH8MbxYTNxi9j7iCQ3g" alt="Screenshot of the Bubble API settings page"><figcaption><p>Bubble API settings</p></figcaption></figure>

Your data types will show up right below. Check the box for every data type that you want to sync, to enable the API for that type.

<figure><img src="/files/HYeyUv0SKAHvmxeTBZbH" alt="Screenshot of the Bubble API settings page data types"><figcaption><p>Bubble data types exposed via the API</p></figcaption></figure>

{% hint style="danger" %}
**Keep "use field display instead of ID for key names" unchecked**\
One more important thing: we strongly recommend making sure that "Use field display instead of ID for key names" is OFF (unchecked). That setting can break your syncing if any type or field names in Bubble are changed.
{% endhint %}

<figure><img src="/files/Y3CmJp7KnbBa9gfIQVaK" alt="Screenshot of the Bubble API settings page with the &#x22;Use field display instead of ID for key names&#x22; option unchecked"><figcaption><p>Please uncheck "Use field display instead of ID for key names"</p></figcaption></figure>

Now you can grab your API key. Look below in the API tokens section. If you already have a token, you can use that. Or, click "Generate a new API token" (1). Then copy the "Private key" (2).

<figure><img src="/files/bAMFg1o9X9s54W3neYyS" alt="Screenshot of the Bubble API settings page with the API key"><figcaption><p>API key</p></figcaption></figure>

#### Getting your Bubble Data API URL

Make sure the settings changes you made in the previous step are published to your live Bubble app. Then, change your view using the menu in the top right, switching from "Development" to "Live" version.

{% hint style="danger" %}
**Warning**: The URL is different if you're looking at the "Development" version of your app and includes an extra "/version-test". Unless you're just testing things, you will likely want to use the production URL without the extra "/version-test".
{% endhint %}

Copy the "Data API root URL" value.

<figure><img src="/files/R9lMzvuLSVQokweB3pzY" alt="Screenshot of the Bubble API settings page with the API URL"><figcaption><p>Data API root URL</p></figcaption></figure>


# Close

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Close

### Supported Objects

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>🤝 Opportunities</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👥 Leads</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👤 Contacts</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>✅ Tasks</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🎛️ Pipelines</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🎲 Opportunity Statuses</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>👥 Users</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>🗒️ Notes</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>📅 Meetings</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>📊 Lead Statuses</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>✉️ Emails</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>📞 Calls</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🏃‍♂️ Activities</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr></tbody></table>

#### Things to Keep in Mind

{% hint style="info" %}
Record deletes for the 'Tasks' table are synced by updating the "is\_complete" property on the destination app (i.e Airtable, Notion).
{% endhint %}

<figure><img src="/files/wpKvCL2fQb4X6YpWLCEj" alt=""><figcaption></figcaption></figure>


# Copper

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Copper

### Supported Objects

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>👤 People</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🏢 Companies</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🤝 Opportunities</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>❌ Opportunity/Loss Reasons</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>📊 Opportunity Pipeline Stages</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>📊 Opportunity Pipelines</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>👥 Contact Types</td><td><span data-option="26a18353ef33429b8325cf29bcbeeb54">➡️ Supported (1-way)</span></td><td></td></tr><tr><td>🏷️ Tags</td><td><span data-option="c915e2668c0b48a88fada9c39263f0c1">✖️ Not supported</span></td><td></td></tr></tbody></table>


# MS Dynamics CRM

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## MS Dynamics CRM

### Supported Objects

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>👥 Accounts</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👤 Contacts</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>📊 Opportunities</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr></tbody></table>

### Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

#### Deleting Accounts or Contacts is best done in MS Dynamics

In MS Dynamics, when you delete an Account, all related Contacts and Opportunities are deleted as well. With the current way the MS Dynamics API is set up, if you delete an Account in Airtable or another synced connector, the corresponding Contacts and Opportunities will have their data erased, but the rows will not be deleted - they'll show up as empty rows.

The easiest way to fix this is to either:

* Delete the emptied rows in Airtable, or
* Delete Accounts in MS Dynamics in the first place

{% embed url="<https://www.loom.com/share/5d302f448e3a4eea95d285340719f164?sid=71e9d4d7-bd0b-41b1-be9f-69ff12ae6f5f>" %}


# Outreach

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Outreach

<figure><img src="/files/Jh4ytl24VMRlYtHO77Wj" alt=""><figcaption></figcaption></figure>

### Supported Objects

<table><thead><tr><th>Tables</th><th>Status<select><option value="e06f8215296841cbb9b56300554bc898" label="✅ Supported" color="blue"></option><option value="26a18353ef33429b8325cf29bcbeeb54" label="➡️ Supported (1-way)" color="blue"></option><option value="17ee2063f0304528872db331d6c89a93" label="✅ Supported (as JSON)" color="blue"></option><option value="c915e2668c0b48a88fada9c39263f0c1" label="✖️ Not supported" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>👤 Accounts</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>✉️ Companies</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>🤝 Opportunities</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr><tr><td>👥 Prospects</td><td><span data-option="e06f8215296841cbb9b56300554bc898">✅ Supported</span></td><td></td></tr></tbody></table>

### Things to Keep in Mind

#### Outreach sets an "Owner is You" filter by default

To view all synced records, make sure you remove the "Owner" filter.

<figure><img src="/files/tKESWqEuN1YHIh2oI9wW" alt="" width="357"><figcaption></figcaption></figure>

#### For Prospects, "Name" is a read-only field

To change how a name looks in Prospects from a synced connector, you should edit the "First Name" and "Last Name" fields.


# Shopify

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Shopify

### Supported Tables

<table><thead><tr><th>Tables</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option><option value="9b0955a85d044258a10aa0d1d3695a79" label="✅ Supported (as JSON)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>Products</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Images</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Options</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Variants</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Collects</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Custom Collections</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Customers</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Inventory</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Blogs</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Pages</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>Orders</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>Locations</td><td><span data-option="bd4357bee12749d0b80f7bc4a94ec3b5">➡️ Supported (1-Way)</span></td><td></td></tr><tr><td>Discount Code</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>Gift Card</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>Transactions</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>Refunds</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>Articles</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

### Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

#### Backing up data

{% hint style="danger" %}
**We strongly recommend using a Shopify Backup service**
{% endhint %}

Two-way sync is very powerful. To protect against manual error and for extra peace of mind, we recommend using a backup service like the one below when using two-way sync :point\_down:

{% embed url="<https://apps.shopify.com/backup>" %}

#### Syncing images

{% hint style="info" %}
**You must create a separate Media table in order to sync product images**
{% endhint %}

See the article below for more details :point\_down:

{% content-ref url="/pages/xIrhwpEUIQU1uxlX4xvB" %}
[Syncing images](/previous-connectors/shopify/syncing-images)
{% endcontent-ref %}

#### Syncing variants

{% hint style="info" %}
**You must create a separate Variants table in order to sync product variants**
{% endhint %}

See the article below for more details :point\_down:

{% content-ref url="/pages/UtqjuX2yKLvcohUBTAEm" %}
[Syncing variants](/previous-connectors/shopify/syncing-variants)
{% endcontent-ref %}


# Authorize Shopify

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Authorize Shopify

### How to get your access token

**1. Go to App and sales channel settings**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/96630f45-4f16-40ad-9232-c9f901445fc3/b2a30be6-32e3-4789-aba4-2edf55db9bb2.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5000&#x26;fp-y=0.5000&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=327&#x26;mark-y=251&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTQlMkNGRjc0NDImdz01MjQmaD0zNSZmaXQ9Y3JvcCZjb3JuZXItcmFkaXVzPTEw" alt=""><figcaption></figcaption></figure>

**2. Click on Develop apps**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/53cc4af1-fc16-403b-8144-954d450647d4/6724fdef-12db-4bcc-89d9-86d40622a9cc.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5000&#x26;fp-y=0.5000&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=853&#x26;mark-y=91&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTQlMkNGRjc0NDImdz05NSZoPTM1JmZpdD1jcm9wJmNvcm5lci1yYWRpdXM9MTA%3D" alt=""><figcaption></figcaption></figure>

**3. Create your app**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/98624e57-6f76-44ee-89d5-80cb7da73094/7de4b427-f4e8-4d00-ace0-74f2944bdcc2.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5000&#x26;fp-y=0.5000&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=364&#x26;mark-y=326&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTQlMkNGRjc0NDImdz00NzQmaD0zNSZmaXQ9Y3JvcCZjb3JuZXItcmFkaXVzPTEw" alt=""><figcaption></figcaption></figure>

**4. Configure Admin API scopes**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/6659a590-7d35-4e65-b750-703f09b5a850/343251e4-ef35-4143-8389-2f4f0cce9221.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5000&#x26;fp-y=0.5000&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=394&#x26;mark-y=382&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTQlMkNGRjc0NDImdz0xNzMmaD0zMCZmaXQ9Y3JvcCZjb3JuZXItcmFkaXVzPTEw" alt=""><figcaption></figcaption></figure>

**5. Make sure to check read and write products**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/0082e259-378c-40b4-92b3-9241feb960b5/a4bf67c8-f43d-4e32-967d-1b4a2f98a2e8.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5012&#x26;fp-y=0.6953&#x26;fp-z=2.2320&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=100&#x26;mark-y=357&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTYlMkNGRjc0NDImdz0xMDAyJmg9MjU5JmZpdD1jcm9wJmNvcm5lci1yYWRpdXM9MTA%3D" alt=""><figcaption></figcaption></figure>

**6. Install your app**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/01b9dce5-677d-4d46-8ef3-376b83c2b273/b89dcb52-cc5a-44c3-8269-25d2a69366ec.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.5000&#x26;fp-y=0.5000&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=994&#x26;mark-y=91&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTQlMkNGRjc0NDImdz04NSZoPTM1JmZpdD1jcm9wJmNvcm5lci1yYWRpdXM9MTA%3D" alt=""><figcaption></figcaption></figure>

**7. Copy your Access token!**

<figure><img src="https://images.tango.us/workflows/bc8daaac-834b-4df3-a66d-a1010968825a/steps/b073da90-5b47-4aed-9b35-6b56b64d1a27/5db75d97-3786-4cf2-aa55-571fafef6e75.png?fm=png&#x26;crop=focalpoint&#x26;fit=crop&#x26;fp-x=0.4631&#x26;fp-y=0.5736&#x26;fp-z=1.7561&#x26;w=1200&#x26;border=2%2CF4F2F7&#x26;border-radius=8%2C8%2C8%2C8&#x26;border-radius-inner=8%2C8%2C8%2C8&#x26;blend-align=bottom&#x26;blend-mode=normal&#x26;blend-x=0&#x26;blend-w=1200&#x26;blend64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL21hZGUtd2l0aC10YW5nby13YXRlcm1hcmstdjIucG5n&#x26;mark-x=316&#x26;mark-y=362&#x26;m64=aHR0cHM6Ly9pbWFnZXMudGFuZ28udXMvc3RhdGljL2JsYW5rLnBuZz9tYXNrPWNvcm5lcnMmYm9yZGVyPTYlMkNGRjc0NDImdz01NjgmaD02MiZmaXQ9Y3JvcCZjb3JuZXItcmFkaXVzPTEw" alt=""><figcaption></figcaption></figure>

### How to get your store name

1\) Go to <https://accounts.shopify.com/store-login>

2\) Copy the values *before* ".my.shopify.com"

e.g. our store name = "whalesync"

<figure><img src="/files/aK8Ughcn7vQQ20OwkWI8" alt=""><figcaption></figcaption></figure>


# Syncing images

How to sync Shopify product images

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Syncing images

{% hint style="info" %}
We suggest using our [Shopify Template Pack](https://www.whalesync.com/template-packs/shopify) which has the correct tables/fields pre-created
{% endhint %}

**TL;DR**

* In order to sync product images, you'll need to create a Media table that is separate from your Products table
* You can then link a Product to Media using a linked record (aka foreign key) field

**Detailed Explanation**

<figure><img src="/files/UJIMkXea6Mi7FGTYoxtC" alt=""><figcaption></figcaption></figure>

1. In Airtable (or your other connected app), create a table called "Media"
2. In the Media table, include at least two fields: 1) Shopify Product ID 2) Image

   <figure><img src="/files/tnWSc4MRbUINKXmVy4WQ" alt=""><figcaption></figcaption></figure>
3. In the Products table, include a linked record from Product to Media

   <figure><img src="/files/bl99Q3BlSKr9HCKWiseh" alt=""><figcaption></figcaption></figure>


# Syncing variants

How to sync Shopify product variants

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Syncing variants

{% hint style="info" %}
We suggest using our [Shopify Template Pack](https://www.whalesync.com/template-packs/shopify) which has the correct tables/fields pre-created
{% endhint %}

### **Summary**

* In order to sync product variants, you'll need to create a Variants table and an Options table that are separate from your Products table
* You can then link a Product to those Options and Variants using a linked record (aka foreign key) field
* If you want to create new Variants from Airtable, you must create them by adding *Options* (just like you would in Shopify).

#### **Detailed Explanation**

<figure><img src="/files/tmiB2SIeS43XyYFld0rk" alt=""><figcaption></figcaption></figure>

1. In Airtable (or your other connected app), create a table called "Variants" and a table called "Options"
2. In your Products table, created linked records (aka foreign keys) from Product to Options and Variants

{% hint style="info" %}
If you want to create new Variants from Airtable, you must create them by adding *Options* (just like you would in Shopify). Editing the Variants table directly will not work.
{% endhint %}

### Limitations

{% hint style="warning" %}
Due to the Shopify API, Whalesync only supports up to 100 Variants. Syncing more than 100 Variants could have unexpected behavior.
{% endhint %}


# Tutorial videos

How to sync Shopify with Airtable & Webflow

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Tutorial videos

#### Syncing Shopify & Airtable

{% embed url="<https://youtu.be/mdfmjvwZH5o>" %}


# Theme Template field

A field that behaves uniquely

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Theme Template field

**TL;DR**

* Shopify's Theme Template field works with 2-way sync BUT you must enter in the value exactly in your connected app

**Detailed Explanation**

Whalesync supports two-way sync of Shopify's Theme Template as shown below:

<figure><img src="/files/XKtfEMt3HgAmXvtA7Tjy" alt=""><figcaption><p>Theme Template in Shopify maps to a Theme Template field in Airtable (or your other connected app)</p></figcaption></figure>

But if you update Theme template in Airtable, you must make sure to input the exact value for a theme that is available in Shopify. If you enter in a value incorrectly, nothing will happen:

<figure><img src="/files/gZl9sA3wt8jzcFQUMijQ" alt=""><figcaption><p>Example of entering in an incorrect value for Theme Template</p></figcaption></figure>


# Webflow E-Commerce

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Webflow E-Commerce

### Supported Collections

<table><thead><tr><th>Field</th><th>Status<select><option value="6c90dea3d4b34f409e73be79b7076c4a" label="✖️ Not Yet" color="blue"></option><option value="9e01356060cc4ea4988d69f72fe19d39" label="✅ Supported" color="blue"></option><option value="bd4357bee12749d0b80f7bc4a94ec3b5" label="➡️ Supported (1-Way)" color="blue"></option></select></th><th data-hidden></th></tr></thead><tbody><tr><td>📦 Products</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>#️ Variants</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🔽 Categories</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🎨 Product Options</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>📂 Product Option Sets</td><td><span data-option="9e01356060cc4ea4988d69f72fe19d39">✅ Supported</span></td><td></td></tr><tr><td>🏷️ Discounts</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>🔢 Inventory</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>💸 Orders</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr><tr><td>💸 Subscriptions</td><td><span data-option="6c90dea3d4b34f409e73be79b7076c4a">✖️ Not Yet</span></td><td></td></tr></tbody></table>

### How to Set Up Webflow E-Comm <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

{% embed url="<https://www.youtube.com/watch?v=OcViUBYHcjE>" %}

### E-Commerce Specific Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

{% hint style="info" %}
**The "Products" collection in Webflow is split into four tables:**\
1\. Products\
2\. Variants\
3\. Product Option Sets\
4\. Product Options
{% endhint %}

Webflow E-Commerce's "Products" table is really a series of small tables. When managing Webflow E-Comm products from other apps (e.g. Airtable), you'll need to sync Products as the four separate tables below:

<figure><img src="/files/1C3fDsdHXHV1pHSIn7qd" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/05UpDPbIZGWK8PXAxEpm" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**You can edit Variants, Production Option Set, and Product Options in your other connector (e.g. Airtable) but you can't create new ones**
{% endhint %}

You can’t currently create new Variants, Product Option Sets, or Product Options in your other connector (e.g. Airtable). If you try to create them, they won’t sync across).

You *can* create new Products though.

{% hint style="info" %}
**Products created in Airtable will sync to Webflow as "staged for publish"**
{% endhint %}

Due to a limitation in Webflow's API, products created in Airtable will sync as "staged for publis&#x68;**"** rather than "published".

You will need to republish Webflow (or each product individually) for them to appear on your live site.

{% hint style="info" %}
**Webflow forces you to recreate variants if you delete Product Options or Option Sets**
{% endhint %}

After you delete Product Options (or Option Sets), Webflow will want to correspondingly adjust the set of variantss the next time you log in and open your Product in the Webflow Products table. It will give you a scarier-than-it-needs-to-be message saying that the variantss are corrupted, and offer to fix them. Click “Recreate variants”. As the message says, make sure the fields are set correctly after.

<figure><img src="/files/mnwzVyFNzdSINMTiztVu" alt=""><figcaption></figcaption></figure>

### General Webflow - Things to Keep in Mind <a href="#h_bccce14d8a" id="h_bccce14d8a"></a>

See the "Things to Keep in Mind" section for Webflow:

{% embed url="<https://docs.whalesync.com/connectors/webflow#h_bccce14d8a>" %}


# Quick Start Guide: WF E-Comm

Tips to help you get started syncing Webflow E-Comm

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## Quick Start Guide: WF E-Comm

#### 1) Start with our template

If syncing Webflow E-Comm with Airtable, we highly recommend starting with our Airtable template:

{% embed url="<https://airtable.com/shr6kzSL2IJ0tg1w3>" %}
Click "Copy base" on the bottom right
{% endembed %}

#### 2) (If not using the template) Make sure to add important tables

You should have at least these five tables:

<figure><img src="/files/1LBChva09rM3lac0ADxG" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
**The Variants table is necessary even if your products don't have variants**

Every product in Webflow has a "variant" even though Webflow doesn't show it.\
\
The Variant record of a Product stores important product information like price.
{% endhint %}

<figure><img src="/files/hRZ7d17kl2tRWHRF4T09" alt=""><figcaption><p>Example where a Webflow product doesn't "have variants" but really does under the hood</p></figcaption></figure>

#### 3) (If not using the template) Make sure to add an "Initial Variant - Price"

You will need to have an "Initial Variant - Price" field in your Products table.

See the below doc to understand why this field is necessary:

{% content-ref url="/pages/XEBPPzooFM7498CSt7Rc" %}
[How to Create Products & Variants](/previous-connectors/webflow-e-commerce/how-to-create-products-and-variants)
{% endcontent-ref %}

#### 4) Read the 'Things to Keep in Mind'

The 'Things to Keep in Mind' section of the doc below walks through concepts that are important to Webflow E-Commerce.

{% content-ref url="/pages/2ht1FXPgpqerPDDg6xrq" %}
[Webflow E-Commerce](/previous-connectors/webflow-e-commerce)
{% endcontent-ref %}

#### 5) Join our Slack channel

If you have any questions, don't hesitate to ask! We love to help :relaxed:.

{% embed url="<https://join.slack.com/t/whalesyncpioneers/shared_invite/zt-r231pg5t-L7GRWvn52GZGm11GbiXX3Q>" %}


# How to Create Products & Variants

Guide to creating e-comm products in Webflow from other apps (like Airtable)

{% hint style="warning" %}
**Archived:** This connector is no longer offered by Whalesync. Existing syncs will continue to run, but future improvements and support will be limited. See [Previous Connectors](/previous-connectors) for more details.
{% endhint %}

## How to Create Products & Variants

### Creating Products

**TL;DR**

1. Make sure to map a linked record field between the Products table and the Variants table
2. Make sure to map an "Initial Variant - Price" field in your Products table
3. Make sure that "Initial Variant - Price" field has a value

<figure><img src="/files/XPvXrc17EivkCIoC8qEf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Note! Due to a limitation in Webflow's API, **products created in Airtable will sync as "staged for publish"** rather than "published".

You will **need to republish Webflow** (or each product individually) for them to appear on your live site.
{% endhint %}

**Detailed Explanation**

To create a new product, Webflow requires that you create the first variant at the same time. Most of the fields in the variant can be supplied later, but the price must be set immediately by providing a value to the "Initial Variant - Price" field.

{% hint style="info" %}
**Tip!**\
Many other variant properties can also be set when a product is first created by mapping the other "Initial Variant" fields.
{% endhint %}

See video below (starting at 4:47) for an overview of creating products with initial variants.

{% embed url="<https://www.youtube.com/watch?v=OcViUBYHcjE&t=287s>" %}

### Creating Variants

{% hint style="info" %}
Currently, Whalesync does not support creating variants for a product.
{% endhint %}

If you need to create variants for a product, you can create them in the Webflow E-Comm UI and they will sync back into your other connected app.




---

[Next Page](/llms-full.txt/1)

