> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://apidocs.polytomic.com/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://apidocs.polytomic.com/_mcp/server. You can have Polytomic Connect sync updates from your sources to [custom webhooks](https://apidocs.polytomic.com/guides/configuring-your-connections/connections/webhooks). You can do this by creating a Model Sync that maps fields from a Polytomic Model to your webhook destination. ## Code example When creating a Model Sync to a custom webhook destination, set each field's `target` to `record`. Additionally, the `target.object` must be `http` and the sync mode is always `updateOrCreate`. The below request creates a Model Sync to a custom webhook: #### cURL ```bash curl --request POST \ --url https://app.polytomic.com/api/syncs \ --header "accept: application/json" \ --header "content-type: application/json" \ --header "Authorization: Bearer ${POLYTOMIC_API_KEY}" \ -d '{ "name": "Sync to Webhook", "active": true, "mode": "updateOrCreate", "fields": [ { "source": { "field": "field1", "model_id": "YOUR_MODEL_ID" }, "target": "record" }, { "source": { "field": "field2", "model_id": "YOUR_MODEL_ID" }, "target": "record" }, { "source": { "field": "field3", "model_id": "YOUR_MODEL_ID" }, "target": "record" } ], "target": { "connection_id": "YOUR_WEBHOOK_CONNECTION_ID", "object": "http", "configuration": { "batch_size": 100, "record_requests": true } }, "schedule": { "frequency": "manual" } }' ``` #### TypeScript ```typescript import { Polytomic, PolytomicClient } from 'polytomic'; const polytomic = new PolytomicClient({ token: "POLYTOMIC_API_KEY", }); polytomic.modelSync.create({ name: "Sync to Webhook", mode: "updateOrCreate", active: true, fields: [ { source: { field: "field1", model_id: "YOUR_MODEL_ID" }, target: "record" }, { source: { field: "field2", model_id: "YOUR_MODEL_ID" }, target: "record" }, { source: { field: "field3", model_id: "YOUR_MODEL_ID" }, target: "record" } ], schedule: { frequency: Polytomic.ScheduleFrequency.Manual }, target: { connection_id: "YOUR_WEBHOOK_CONNECTION_ID", object: "http", configuration: { batch_size: 100, record_requests: true } } }).then((resp) => { console.log(resp); }) ``` #### Python ```python import os from polytomic.client import Polytomic from polytomic import ModelSyncField, Source, Identity, Schedule, ScheduleFrequency, Target client = Polytomic( token=os.getenv("POLYTOMIC_API_KEY"), ) resp = client.model_sync.create( name="Sync to Webhook", active="true", mode="updateOrCreate", fields=[ ModelSyncField( source=Source(field="field1", model_id="YOUR_MODEL_ID"), target="record", ), ModelSyncField( source=Source(field="field2", model_id="YOUR_MODEL_ID"), target="record", ), ModelSyncField( source=Source(field="field3", model_id="YOUR_MODEL_ID"), target="record", ), ], target=Target(connection_id="YOUR_WEBHOOK_CONNECTION_ID", object="http", configuration={batch_size: 100, record_requests: true}), schedule=Schedule( frequency=ScheduleFrequency.MANUAL ) ) print(resp.data) ``` #### 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.ModelSync.Create( context.TODO(), &polytomic.CreateModelSyncRequest{ Name: "Sync to Webhook", Active: true, Mode: "updateOrCreate", Fields: []*polytomic.ModelSyncField{ { Source: &polytomic.Source{ Field: "field1", ModelId: "YOUR_MODEL_ID", }, Target: "record", }, { Source: &polytomic.Source{ Field: "field2", ModelId: "YOUR_MODEL_ID", }, Target: "record", }, }, Target: &polytomic.Target{ ConnectionId: "YOUR_WEBHOOK_CONNECTION_ID", Object: "http", Configuration: map[string]any{ "batch_size": 100, "record_requests": true } }, Schedule: &polytomic.Schedule{ Frequency: pointer.ToString(string(polytomic.ScheduleFrequencyManual)), } } ) if err != nil { panic(err) } fmt.Println(resp) ``` ## Payload format Polytomic's payloads will arrive in this format: ``` POST /path/to/api HTTP/1.1 Host: mysite.com Accept-Encoding: gzip Content-Type: application/json Polytomic-Signature-Timestamp: 2021-06-01T22:55:36Z Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ3ZWJob29rIiwianRpIjoiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIiwiaXNzIjoiaHR0cHM6Ly9hcHAucG9seXRvbWljLWxvY2FsLmNvbTo4NDQzLyJ9.FBSU_fC1YFyWhMSPErRono4BPfkIeT3MkRdZrepiP3c Content-Length: 646 User-Agent: Polytomic/rel2021.05.25 { "event": "sync.records", "object": { "id": "1ea8f90a-b22e-4218-86d5-c3c109e1fbb7", "name": "Webhook HTTP Endpoint sync", "records": [ { "hash": "b7421c6c57bd49f7", "fields": { "email": "nathan@polytomic.com", "last_login": "2020-12-02T00:00:00Z" } }, ... ] } } ``` ## Payload explanation ### Headers #### Accept-Encoding Polytomic delivers payloads as a gzipped response to minimize bandwidth use. Your client likely supports decoding this automatically. #### Content-Type Polytomic delivers its webhooks payloads as json only. This header will always be present. #### Polytomic-Signature-Timestamp This signature lets your backend know when the request was created. In the future it may be used in combination with message signing to provide security. In general, it is a good idea to reject requests older than you expect (more than a few minutes old). #### Authorization This should be Bearer token matching the same value that was provided as the Secret during connection setup. For now, this is the only request authorization and is a static value. ### Body ``` { # This is an event type to help you distinguish new and future hooks. # You should only process webhooks you know about—for right now, that is # just the sync.records event. "event": "sync.records", # Object is an envelope that will contain the payload, regardless of event "object": { # This is the ID of the sync that the webhook is for. It will match # the value seen the URL bar when you have the corresponding sync # configuration open. "id": "1ea8f90a-b22e-4218-86d5-c3c109e1fbb7", # This name matches the sync setup you created in Polytomic. It can be # useful for discriminating against data coming in from different endpoints. "name": "Webhook HTTP Endpoint sync", # This a list of the records changed since the last payload. "records": [ { # hash is a computed hash of the record's fields key/values pairs, which # may be useful for deduplicating incoming data. "hash": "b7421c6c57bd49f7", # Fields contains each of the fields you selected to be delivered. "fields": { "email": "nathan@polytomic.com", "last_login": "2020-12-02T00:00:00Z" } }, ... ], "metadata": { # Any key-value pairs of metadata defined in the sync configuration } } } ``` ### Field normalization Polytomic will strip away characters from your field names that do not match any of these criteria: * Alphanumeric * Underscores * Hyphens * Periods or full stops For example, if your source field is named `$first_name`, your webhook payload will contain the field `first_name` because the `$` character does not match any of the above criteria. This normalization can be turned off if you desire. ## Whitelist IPs Requests will arrive from Polytomic IP addresses. You may need to whitelist them if your webhook host is behind a firewall. You can find the list of Polytomic IP addresses [here](https://apidocs.polytomic.com/guides/ip-whitelisting). ## Payload API response On receipt of the payload, your API should return `200 OK`. Any `4xx` or `5xx` error will cause Polytomic to declare the sync to have failed.