> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://apidocs.polytomic.com/2024-02-08/guides/code-examples/joined-model-sync-from-postgres-airtable-and-stripe-to-hubspot/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://apidocs.polytomic.com/_mcp/server. ## UI demo video Watch the same steps in the Polytomic admin console in this [demo video](https://www.loom.com/share/c1ad006afab745f2be4fb5fc045ed6f5?sid=64833894-47d3-48bb-bc8b-b0ecf1e196c8). ## Code Set your Polytomic API key as an environment variable: ```bash export POLYTOMIC_API_KEY=YOUR-API-TOKEN ``` This example covers three steps: 1. Create Airtable, Stripe, Postgres, and HubSpot Connections. 2. Join the Airtable, Stripe, and Postgres data with Polytomic models. 3. Sync the joined data to HubSpot. ## Step 1: Create Connections The following request creates an Airtable Connection. See the [Airtable connection configuration](/guides/configuring-your-connections/connections/airtable) for the required fields. #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/connections \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Airtable Connection", "type": "airtable", "configuration": {} }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.connections.create( name="Airtable Connection", type="airtable", configuration={} ) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.connections.create({ name: "Airtable Connection", type: "airtable", configuration: {}, }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Connections.Create( context.TODO(), &polytomic.CreateConnectionRequestSchema{ Name: "Airtable Connection", Type: "airtable", Configuration: map[string]interface{}{}, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` Airtable Connections authenticate with OAuth. Open the URL returned in the `auth_url` field of the response to complete the flow. > **OAuth redirection** > > By default, the API expects `auth_url` to open in a new browser window. > Set the optional `redirect_url` parameter in the request body to change > the redirect target. The following request creates a Postgres Connection. See the [Postgres connection configuration](/guides/configuring-your-connections/connections/postgres) for the required fields. The PostgreSQL server must be reachable from Polytomic over the network. #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/connections \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Postgres Connection", "type": "postgresql", "configuration": { "hostname": "localhost", "port": 5432, "database": "postgres", "username": "user", "password": "secret" } }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.connections.create( name="Postgres Connection", type="postgresql", configuration={ "hostname": "localhost", "port": 5432, "database": "postgres", "username": "user", "password": "secret" }) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.connections.create({ name: "Postgres Connection", type: "postgresql", configuration: { hostname: "localhost", port: 5432, database: "postgres", username: "user", password: "secret" }, }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Connections.Create( context.TODO(), &polytomic.CreateConnectionRequestSchema{ Name: "Postgres Connection", Type: "postgresql", Configuration: map[string]interface{}{ "hostname": "localhost", "port": 5432, "database": "postgres", "username": "user", "password": "secret", }, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` The following request creates a Stripe Connection. See the [Stripe connection configuration](/guides/configuring-your-connections/connections/stripe) for the required fields. #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/connections \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Stripe Connection", "type": "stripe", "configuration": { "api_key": "sk_test_4eC39HqLyjWDarjtT1zdp7dc" } }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.connections.create( name="Stripe Connection", type="stripe", configuration={ "api_key": "sk_test_4eC39HqLyjWDarjtT1zdp7dc" }) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.connections.create({ name: "Stripe Connection", type: "stripe", configuration: { api_key: "sk_test_4eC39HqLyjWDarjtT1zdp7dc" }, }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Connections.Create( context.TODO(), &polytomic.CreateConnectionRequestSchema{ Name: "Stripe Connection", Type: "stripe", Configuration: map[string]interface{}{ "api_key": "sk_test_4eC39HqLyjWDarjtT1zdp7dc", }, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` The following request creates a HubSpot Connection. See the [HubSpot connection configuration](/guides/configuring-your-connections/connections/hubspot) for the required fields. #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/connections \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{"name": "HubSpot Connection","type": "hubspot", "configuration": {}}' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.connections.create( name="HubSpot Connection", configuration={}, type="hubspot" ) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.connections.create({ name: "HubSpot Connection", type: "hubspot", configuration: {}, }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Connections.Create( context.TODO(), &polytomic.CreateConnectionRequestSchema{ Name: "HubSpot Connection", Type: "hubspot", Configuration: map[string]interface{}{}, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` HubSpot Connections authenticate with OAuth. Open the URL returned in the `auth_url` field of the response to complete the flow. > **OAuth Redirection** > > By default, the API expects the `auth_url` to be open in a new browser window. If you'd like to modify the redirect behavior, there is an optional `redirect_url` parameter that can be added to the request body. ## Step 2: Create joined models The following request creates a `User Details` model over the Postgres `users` table: #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/models \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "User Details", "configuration": { "table": "users" }, "connection_id": "YOUR-POSTGRES-CONNECTION-ID" }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.models.create( name="User Details", configuration={ "table": "users" }, connection_id="YOUR-POSTGRES-CONNECTION-ID" ) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.models.create({ name: "User Details", configuration: { table: "users" }, connection_id: "YOUR-POSTGRES-CONNECTION-ID", }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Models.Create( context.TODO(), &polytomic.CreateModelRequest{ Name: "User Details", Configuration: map[string]interface{}{ "table": "users", }, ConnectionId: "YOUR-POSTGRES-CONNECTION-ID", }, ) if err != nil { panic(err) } fmt.Println(resp) ``` The following request creates a `Customers` model from Stripe, joined to `User Details` on the `email` field: #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/models \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Customers", "configuration": { "stream_id": "customers" }, "fields": ["balance", "description", "livemode"], "relations": [ { "from": "email", "to": { "field": "email", "model_id": "YOUR-POSTGRES-MODEL-ID" } } ], "connection_id": "YOUR-STRIPE-CONNECTION-ID" }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.models.create( name="Customers", configuration={ "stream_id": "customers" }, fields=["balance", "description", "livemode"], relations=[ ModelRelation(**{ "from": "email", "to": ModelRelationTo( field="email", model_id="YOUR-POSTGRES-MODEL-ID") } ), ], connection_id="YOUR-STRIPE-CONNECTION-ID" ) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.models.create({ name: "Customers", configuration: { stream_id: "customers" }, fields: ["balance", "description", "livemode"], relations: [ { from: "email", to: { model_id: "YOUR-POSTGRES-MODEL-ID", field: "email" } } ], connection_id: "YOUR-STRIPE-CONNECTION-ID", }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" "github.com/AlekSi/pointer" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Models.Create( context.TODO(), &polytomic.CreateModelRequest{ Name: "Customers", Configuration: map[string]interface{}{ "stream_id": "customers", }, Fields: []string{"balance", "description", "livemode"}, ConnectionId: "YOUR-STRIPE-CONNECTION-ID", Relations: []*polytomic.ModelRelation{ { From: pointer.ToString("email"), To: &polytomic.ModelRelationTo{ ModelId: pointer.ToString("YOUR-POSTGRES-MODEL-ID"), Field: pointer.ToString("email"), }, }, }, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` The following request creates a `Stars Data` model from Airtable, joined to `User Details` on the `email` field: #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/models \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "X-Polytomic-Version: 2024-02-08" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Customers", "configuration": { "tableobj": { "value": "tblOuVBnPKvXjYhqP", "label": "Table 1" }, "viewobj": {}, "baseobj": { "value": "appDVrQJeb9w2F2IL", "label": "User sample" }, "fields": ["fldR3dERuDqosnxFY"], "relations": [ { "from": "fldR3dERuDqosnxFY", "to": { "field": "email", "model_id": "YOUR-POSTGRES-MODEL-ID" } } ], "connection_id": "YOUR-AIRTABLE-CONNECTION-ID" }' ``` #### Python ```python import os from polytomic.client import Polytomic client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.models.create( name="Stars Data", configuration={ "tableobj": { "value": "tblOuVBnPKvXjYhqP", "label": "Table 1", }, "viewobj": {}, "baseobj": { "value": "appDVrQJeb9w2F2IL", "label": "User sample", }, }, fields=["fldah5pg1Q9k3PmEH"], # 'Stars' field relations=[ ModelRelation(**{ "from": "fldR3dERuDqosnxFY", "to": ModelRelationTo( field="email", model_id="YOUR-POSTGRES-MODEL-ID") } ), ], connection_id="YOUR-AIRTABLE-CONNECTION-ID" ) print(resp.data) ``` #### Typescript ```typescript import { PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.models.create({ name: "Stars Data", configuration: { tableobj: { value: "tblOuVBnPKvXjYhqP", label: "Table 1", }, viewobj: {}, baseobj: { value: "appDVrQJeb9w2F2IL", label: "User sample", }, }, fields: ["fldah5pg1Q9k3PmEH"], // 'Stars' field relations: [ { from: "fldR3dERuDqosnxFY", to: { model_id: "YOUR-POSTGRES-MODEL-ID", field: "email" } } ], connection_id: "YOUR-AIRTABLE-CONNECTION-ID", }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" "github.com/AlekSi/pointer" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.Models.Create( context.TODO(), &polytomic.CreateModelRequest{ Name: "Stars Data", Configuration: map[string]interface{}{ "tableobj": map[string]interface{}{ "value": "tblOuVBnPKvXjYhqP", "label": "Table 1", }, "viewobj": map[string]interface{}{}, "baseobj": map[string]interface{}{ "value": "appDVrQJeb9w2F2IL", "label": "User sample", }, }, Fields: []string{"fldah5pg1Q9k3PmEH"}, // 'Stars' field ConnectionId: "YOUR-AIRTABLE-CONNECTION-ID", Relations: []*polytomic.ModelRelation{ { From: pointer.ToString("fldR3dERuDqosnxFY"), To: &polytomic.ModelRelationTo{ ModelId: pointer.ToString("YOUR-POSTGRES-MODEL-ID"), Field: pointer.ToString("email"), }, }, }, }, ) if err != nil { panic(err) } fmt.Println(resp) ``` ## Step 3: Sync the joined data to HubSpot The following request creates a Model Sync that loads the joined data into HubSpot: #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/syncs \ --header 'X-Polytomic-Version: 2024-02-08' \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ --header 'content-type: application/json' \ -d '{ "name": "Customer data to HubSpot Sync", "mode": "updateOrCreate", "fields": [ { "source": { "model_id": "YOUR-POSTGRES-MODEL-ID", "field": "first_name" }, "target": "firstname" }, { "source": { "model_id": "YOUR-POSTGRES-MODEL-ID", "field": "last_name" }, "target": "lastname" }, { "source": { "model_id": "YOUR-AIRTABLE-MODEL-ID", "field": "fldah5pg1Q9k3PmEH" }, "target": "kloutscoregeneral" }, { "source": { "model_id": "YOUR-STRIPE-MODEL-ID", "field": "description" }, "target": "subscription_plan" } ], "schedule": { "frequency": "continuous" }, "identity": { "source": { "model_id": "YOUR-POSTGRES-MODEL-ID", "field": "email" }, "target": "email", "function": "Equality" }, "target": { "connection_id": "YOUR-HUBSPOT-CONNECTION-ID", "object": "contacts" } }' ``` #### Python ```python import os from polytomic.client import Polytomic from polytomic import Identity, ModelSyncField, Schedule, Source, Target, ScheduleFrequency client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.model_sync.create( name="Customer data to HubSpot Sync", mode="updateOrCreate", identity=Identity( source=Source( field= "email", model_id= "YOUR-POSTGRES-MODEL-ID" ), target="email", ), fields=[ ModelSyncField( source=Source( field="first_name", model_id="YOUR-POSTGRES-MODEL-ID" ), target="firstname", ), ModelSyncField( source=Source( field="last_name", model_id="YOUR-POSTGRES-MODEL-ID" ), target="lastname", ), ModelSyncField( source=Source( field="fldah5pg1Q9k3PmEH", model_id="YOUR-AIRTABLE-MODEL-ID" ), target="kloutscoregeneral", ), ModelSyncField( source=Source( field="description", model_id="YOUR-STRIPE-MODEL-ID" ), target="subscription_plan", ), ], schedule=Schedule( frequency=ScheduleFrequency.CONTINUOUS, ), target=Target( connection_id="YOUR-HUBSPOT-CONNECTION-ID", object="contacts", ) ) print(resp.data) ``` #### Typescript ```typescript import { Polytomic, PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.modelSync.create({ name: "Customer data to HubSpot Sync", mode: "updateOrCreate", fields: [ { source: { model_id: "YOUR-POSTGRES-MODEL-ID", field: "first_name" }, target: "firstname" }, { source: { model_id: "YOUR-POSTGRES-MODEL-ID", field: "last_name" }, target: "lastname" }, { source: { model_id: "YOUR-AIRTABLE-MODEL-ID", field: "fldah5pg1Q9k3PmEH" }, target: "kloutscoregeneral" }, { source: { model_id: "YOUR-STRIPE-MODEL-ID", field: "description" }, target: "subscription_plan" } ], schedule: { frequency: Polytomic.ScheduleFrequency.Continuous }, identity: { source: { model_id: "YOUR-POSTGRES-MODEL-ID", field: "email" }, target: "email", function: "Equality" }, target: { connection_id: "YOUR-HUBSPOT-CONNECTION-ID", object: "contacts", } }).then((res) => { console.log(res) }) ``` #### Go ```golang import ( "context" "fmt" "github.com/AlekSi/pointer" polytomic "github.com/polytomic/polytomic-go" polytomicgoclient "github.com/polytomic/polytomic-go/client" "github.com/polytomic/polytomic-go/option" ) client := polytomicgoclient.NewClient( option.WithToken(os.Getenv("POLYTOMIC_API_TOKEN")), ) resp, err := client.ModelSync.Create( context.TODO(), &polytomic.CreateModelSyncRequest{ Name: "Customer data to HubSpot Sync", Mode: "updateOrCreate", Identity: &polytomic.Identity{ Source: &polytomic.Source{ Field: "email", ModelId: "YOUR-POSTGRES-MODEL-ID", }, Target: "email", Function: "Equality", }, Fields: []*polytomic.ModelSyncField{ { Source: &polytomic.Source{ Field: "first_name", ModelId: "YOUR-POSTGRES-MODEL-ID", }, Target: "firstname", }, { Source: &polytomic.Source{ Field: "last_name", ModelId: "YOUR-POSTGRES-MODEL-ID", }, Target: "lastname", }, { Source: &polytomic.Source{ Field: "fldah5pg1Q9k3PmEH", ModelId: "YOUR-AIRTABL-MODEL-ID", }, Target: "kloutscoregeneral", }, { Source: &polytomic.Source{ Field: "description", ModelId: "YOUR-STRIP-MODEL-ID", }, Target: "subscription_plan", }, }, Schedule: &polytomic.Schedule{ Frequency: pointer.ToString(string(polytomic.ScheduleFrequencyContinuous)), }, Target: &polytomic.Target{ ConnectionId: "YOUR-HUBSPOT-CONNECTION-ID", Object: "contacts", }, }, ) if err != nil { panic(err) } fmt.Println(resp) ```