> 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/events/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://apidocs.polytomic.com/_mcp/server. 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](/api-reference/events/list). * 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 ```json { "type": "bulk_sync.running", "event": { "name": "Asana to BigQuery sync", "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83", "sync_id": "dcc891b3-4a25-4b8b-bba8-48104cd66525", "execution_id": "8114c8cc-99fc-4fb4-ab72-28308762fa63", "source_connection_id": "ad56197c-1bca-4256-a410-fb1ffde295c0", "destination_connection_id": "318dba62-d875-11ed-b59b-ea7534cffcab" } } ``` \ ```json { "type": "bulk_sync.completed", "event": { "name": "Asana to BigQuery sync", "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83", "sync_id": "dcc891b3-4a25-4b8b-bba8-48104cd66525", "execution_id": "8114c8cc-99fc-4fb4-ab72-28308762fa63", "source_connection_id": "ad56197c-1bca-4256-a410-fb1ffde295c0", "destination_connection_id": "318dba62-d875-11ed-b59b-ea7534cffcab" } } ``` \ ```json { "type": "sync.running", "event": { "name": "Salesforce Sync", "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83", "execution_id": "2a42c650-b741-4282-a4c7-19de797aa18b", "sync_id": "d09ceb2a-1641-4dc8-bdfe-d019d8964043", "target_connection_id": "7c67e0b3-9759-44eb-b96c-2a7042b583f0" } } ``` \ ```json { "type": "sync.completed", "event": { "name": "Salesforce Sync", "organization_id": "be80a27e-0e80-4dcb-bee9-1666f02eeb83", "sync_id": "d09ceb2a-1641-4dc8-bdfe-d019d8964043", "execution_id": "2a42c650-b741-4282-a4c7-19de797aa18b", "status": "completed", "total_records": [ "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" ], "inserted_records": null, "updated_records": [ "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", "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" "trigger": "manual", "target_connection_id": "7c67e0b3-9759-44eb-b96c-2a7042b583f0" } } ``` ## Consuming events The following Go example receives a webhook delivery and verifies the HMAC signature: ```go package main import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "io/ioutil" "net/http" "github.com/gin-gonic/gin" ) var key = []byte("somepassword") func main() { r := gin.Default() r.POST("/webhook", func(c *gin.Context) { body, _ := ioutil.ReadAll(c.Request.Body) hash := c.Request.Header.Get("Polytomic-Signature") sig, err := hex.DecodeString(hash) if err != nil { panic(err) } mac := hmac.New(sha256.New, key) mac.Write(body) if !hmac.Equal(sig, mac.Sum(nil)) { panic("Invalid signature") } fmt.Printf("Headers: %+v, Body: %s", c.Request.Header, string(body)) c.Status(http.StatusOK) }) r.Run("0.0.0.0:8000") } ```