For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Log inBook a demo
GuidesAPI Reference
GuidesAPI Reference
  • Getting started
    • Introduction
    • IP Whitelisting
    • Obtaining API keys
    • LLMs.txt
    • MCP server
    • Quickstart
    • Native clients
    • Concepts
    • Embedding authentication
    • Multitenancy
    • Versioning
    • Idempotent requests
    • Events
    • Self-hosted option
    • 2025-09-18 Migration Guide
  • Configuring your connections
    • Overview
    • CDC streaming from databases
    • Syncing to custom webhooks
  • Code examples
    • Overview
    • Bulk sync (ELT) from HubSpot to PostgreSQL
    • Bulk sync (ELT) from Salesforce to S3
    • Bulk sync (ELT) from Salesforce to Snowflake
    • Model sync (Reverse ETL) from Snowflake query to Salesforce
    • Model sync (Reverse ETL) from MongoDB to Salesforce
    • Adding users from Snowflake to Salesloft Cadence
    • Adding contacts from Snowflake to Gong Engage
    • Joined model sync from Postgres, Airtable, and Stripe to Hubspot
    • Model sync from MySQL to Snowflake
    • Model sync from Salesforce to Netsuite
    • Querying Salesforce using SOQL
    • Syncing audiences from Snowflake to LinkedIn Ads
    • Syncing contacts from Google Cloud Storage to Salesforce
    • Syncing contacts from Google Cloud Storage to webhooks
    • Transactional calls with LinkedIn Ads audiences
  • Terraform examples
    • Overview
    • Model sync (Reverse ETL) from BigQuery to Salesforce
    • Model sync (Reverse ETL) from BigQuery to LinkedIn Ads
Logo
Log inBook a demo
On this page
  • Event types
  • Webhooks
  • HMAC validation
  • Delivery
  • Record logs
  • Event payload examples
  • Consuming events
Getting started

Events

Was this page helpful?
Previous

Self-hosted option

Next

Events notify you when important actions happen inside an organization. For example, Polytomic emits a sync.completed event every time a sync finishes.

You can consume events in two ways:

  • Poll the events endpoint.
  • Register a webhook to receive events in real time.

⚠️ At-most-once delivery

Polytomic delivers each event at most once and does not re-send events after delivery. If you need guaranteed processing of every change, build a fallback that polls the events endpoint in addition to consuming the webhook.

Retention

Polytomic retains events for 48 hours. After that they are no longer available from the events endpoint.

Event types

The event types are as follows:

  • sync.running
  • sync.failed
  • sync.canceled
  • sync.completed
  • sync.completed_with_errors
  • bulk_sync.running
  • bulk_sync.completed
  • bulk_sync.canceled
  • bulk_sync.failed
  • bulk_sync.completed_with_error

Webhooks

Create and manage webhooks through the webhook API endpoints. A webhook fires events for the organization it belongs to. Each organization can have one webhook.

HMAC validation

Use HMAC validation to confirm that a delivered event came from Polytomic. When you create or update a webhook, you supply a secret. Polytomic signs each delivery with that secret and passes the signature in the Polytomic-Signature header. Compute the same HMAC on the request body and compare.

Delivery

Your endpoint must return a 2xx status code. If it does not, Polytomic retries the delivery up to five times with exponential backoff. Event ordering is not guaranteed.

Record logs

The sync.completed event payload (see the example below) includes links to JSON logs of the records Polytomic inserted or updated. See the total_records, inserted_records, and updated_records fields.

Event payload examples

1{
2 "type": "bulk_sync.running",
3 "event": {
4 "name": "Asana to BigQuery sync",
5 "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83",
6 "sync_id": "dcc891b3-4a25-4b8b-bba8-48104cd66525",
7 "execution_id": "8114c8cc-99fc-4fb4-ab72-28308762fa63",
8 "source_connection_id": "ad56197c-1bca-4256-a410-fb1ffde295c0",
9 "destination_connection_id": "318dba62-d875-11ed-b59b-ea7534cffcab"
10 }
11}

1{
2 "type": "bulk_sync.completed",
3 "event": {
4 "name": "Asana to BigQuery sync",
5 "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83",
6 "sync_id": "dcc891b3-4a25-4b8b-bba8-48104cd66525",
7 "execution_id": "8114c8cc-99fc-4fb4-ab72-28308762fa63",
8 "source_connection_id": "ad56197c-1bca-4256-a410-fb1ffde295c0",
9 "destination_connection_id": "318dba62-d875-11ed-b59b-ea7534cffcab"
10 }
11}

1{
2 "type": "sync.running",
3 "event": {
4 "name": "Salesforce Sync",
5 "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83",
6 "execution_id": "2a42c650-b741-4282-a4c7-19de797aa18b",
7 "sync_id": "d09ceb2a-1641-4dc8-bdfe-d019d8964043",
8 "target_connection_id": "7c67e0b3-9759-44eb-b96c-2a7042b583f0"
9 }
10}

1{
2 "type": "sync.completed",
3 "event": {
4 "name": "Salesforce Sync",
5 "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83",
6 "sync_id": "d09ceb2a-1641-4dc8-bdfe-d019d8964043",
7 "execution_id": "2a42c650-b741-4282-a4c7-19de797aa18b",
8 "status": "completed",
9 "total_records": [
10 "https://app.polytomic.com/api/syncs/54d2d580-d910-4bc7-834b-92d57ca89762/executions/c9fd1b24-0b00-46e8-905b-839f919adffd/records/log1688189538-0d74ec71-4540-4706-867f-e6263070e058.json"
11 ],
12 "inserted_records": null,
13 "updated_records": [
14 "https://app.polytomic.com/api/syncs/54d2d580-d910-4bc7-834b-92d57ca89762/executions/c9fd1b24-0b00-46e8-905b-839f919adffd/updates/log1688189542-05f04ffa-3c85-41eb-8333-9d951f93405b.json",
15 "https://app.polytomic.com/api/syncs/54d2d580-d910-4bc7-834b-92d57ca89762/executions/c9fd1b24-0b00-46e8-905b-839f919adffd/updates/log1688189552-6c0bcf4a-b1ae-4cf5-8ee2-dcb6d6fbb728.json"
16 "trigger": "manual",
17 "target_connection_id": "7c67e0b3-9759-44eb-b96c-2a7042b583f0"
18 }
19}

Consuming events

The following Go example receives a webhook delivery and verifies the HMAC signature:

1package main
2
3import (
4 "bytes"
5 "crypto/hmac"
6 "crypto/sha256"
7 "encoding/hex"
8 "fmt"
9 "io/ioutil"
10 "net/http"
11
12 "github.com/gin-gonic/gin"
13)
14
15var key = []byte("somepassword")
16
17func main() {
18 r := gin.Default()
19
20 r.POST("/webhook", func(c *gin.Context) {
21 body, _ := ioutil.ReadAll(c.Request.Body)
22 hash := c.Request.Header.Get("Polytomic-Signature")
23 sig, err := hex.DecodeString(hash)
24 if err != nil {
25 panic(err)
26 }
27 mac := hmac.New(sha256.New, key)
28 mac.Write(body)
29
30 if !hmac.Equal(sig, mac.Sum(nil)) {
31 panic("Invalid signature")
32 }
33
34 fmt.Printf("Headers: %+v, Body: %s", c.Request.Header, string(body))
35 c.Status(http.StatusOK)
36 })
37
38 r.Run("0.0.0.0:8000")
39}